Malicious Packages in NPM and PyPI: How Typosquatting Threatens Developers

This article originally published on my personal website, protsenko.dev.

Malicious packages lurk in NPM and PyPI — especially in NPM. If you’ve built front-end apps, you’ve likely used npm, pnpm, or yarn. You’ve probably tweaked package.json or run npm add something.

These tools streamline dependency management. Each install pulls code from npmjs.com and runs scripts locally — sometimes with deep system access.

Uploading to these registries requires little effort. Hackers exploit this by releasing deceptive packages with typo-based names or minor variations. One wrong keystroke installs malware disguised as a trusted library. This tactic, known as typosquatting, compromises machines and hijacks developer trust.

Examples of Recent Attacks

Hackers still exploit typosquatting by uploading malicious packages to public repositories. They target both widely used libraries and those with loyal user bases.

Malicious packages **eslint** and **@types/node** (November 2024): In November 2024, hackers uploaded a malicious npm package named @typescript_eslinter/eslint using a fake scope to mimic the legitimate @typescript-eslint package. The malicious package became so popular that it gained hundreds of downloads daily.

Another example is @types-node, which also turned out to be a fake package. It managed to attract nearly a thousand downloads per day. Read more in the source article.

Targeted attack to steal Solana: Hackers also targeted the Solana SDK by deploying malicious packages with names like solana-transaction-toolkit and solana-stable-web-huks. These malicious packages were explicitly designed to steal Solana from wallets. Read more in the source article.

How Attackers Disguise Malicious Packages

Typosquatting in package managers mirrors domain name scams — attackers count on subtle typos developers often miss.

1. Name Mimicry: Attackers impersonate popular libraries by tweaking package names. They swap letters with nearby keys, omit characters, switch adjacent letters, duplicate them, or replace symbols — like dots with underscores or hyphens with lookalikes.

2. Abusing Installation Scripts: NPM lets packages define lifecycle scripts — like preinstall or postinstall—that runs automatically during installation. This opens a common path for malware. A malicious package can execute code the moment someone runs npm install, without any extra action from the developer. Attackers regularly exploit this.

These scripts can steal private data, open reverse shells, or drop obfuscated code with full system access. Fortunately, you can skip them by running npm install --ignore-scripts.

Example of the malicious script in postinstall

3. Combosquatting / Brandjacking: Hackers sometimes append words to trusted package names to hijack brand reputation. In one campaign targeting Roblox developers, they published packages like noblox.js-async and noblox.js-proxy-server—variants meant to mimic the legitimate noblox.js library.

4. Starjacking: Some attackers link malicious packages to popular GitHub repos. Since registries don’t verify these links, a sketchy package can point to a legit, star-heavy repo — tricking users into trusting it at a glance.

For example, I found a typo-squatted package linked to the original repo—one with over 100,000 stars—making it look legitimate at first glance.

5. Copying Metadata: To pass as legitimate, attackers clone metadata — README, versions, descriptions, and keywords. Some even reuse original source code, injecting obfuscated malware to avoid detection. In the TypeScript ESLint typosquat, a package by typescript_eslinter mimicked typescript-eslint, linking to a fake GitHub repo that mirrored the real project’s structure.

These techniques prey on trust and human error. They exploit the belief that official registries are safe and take advantage of how seamlessly tools like NPM install packages.

My Research

I ran a small experiment to see how deep the rabbit hole goes—how many typo-squatted names I could generate and how many remained available for publishing.

Methodology

Simple process:

  • Collected popular NPM package names

  • Generated mimicry names using known deception techniques

  • Checked availability for publishing

Trending package names are easy to find — many curated lists track them. I used one dataset and wrote a Python script to generate lookalike names. From nearly 2,000 original packages, I created 227,389 variations.

Mutation Techniques

To generate typo-squatted variations, I applied the following mutations to each package name:

  • Letter swap: Replaced one letter with its QWERTY keyboard neighbor or with a nearby letter in the name

  • Letter removal: Removed one letter at a time, skipping the scope symbol (@) and dashes

  • Letter duplication: Duplicated one letter at a time across the name

  • Symbol replacement: Swapped symbols — like changing hyphens (-) to underscores (_)

  • Letter insertion: Inserted a keyboard-neighbor letter after each character in sequence

I found a GitHub project that indexes all existing NPM package names. With it, I filtered mutated names against real ones to identify available packages. To double-check, I revalidated missing names using the npmjs.com API.

In total, I generated over 222,000 package name variations available for publishing. About 4,500 were already taken, and a small number failed due to validation errors or malformed mutations.

My research uncovered thousands of typosquatting packages—some already published, others still available. Many squatted packages contained malicious code and were removed from NPM. Yet others, typo-ridden but seemingly harmless, remain live and get downloads weekly.

They often link to official repositories and appear legitimate — until you notice the subtle typo. Even if a package looks clean now, that doesn’t guarantee it will stay that way.

Typosquatting remains a serious attack vector, especially for popular packages, but the situation is not as bad as it seems. Registries like npmjs.com now block names that closely resemble existing ones, such as those differing by only one letter.

Cybersecurity firms also monitor new packages and updates to catch threats early. Still, some slip through. A package might be installed before it’s flagged and removed.

Even a single infection can prove dangerous. Developers can access private codebases, credentials, and infrastructure, making them prime targets.

Protecting Against Those Attacks

Some tools scan build files for known malicious dependencies but only flag what has already been identified. Unknown threats still slip through.

Antivirus software can help post-installation by catching crypto-lockers, stealers, and other malware types. Still, technical tools alone can’t guarantee safety.

Ultimately, protecting yourself requires vigilance. Here are a few practical tips to reduce the risk of installing malicious packages:

1. Double-check package names: Typosquatting only works if you mistype. Always verify the exact name before installing a package.

2. Inspect before installing: Before adding a dependency — especially an obscure one — check its NPM page. Look at the README, version history, and publisher profile. Red flags: vague descriptions, recent creation, or a publisher with no other packages.

3. Use trusted sources: Follow links from official websites or GitHub repositories instead of relying solely on NPM search results.

4. Lock down versions: Use package-lock.json or yarn.lock to freeze dependency versions. Lock files help ensure consistency and avoid unexpected package changes.

5. Watch for unusual behavior: Pay attention to post-install messages or prompts. Legitimate libraries shouldn’t contact remote servers or request elevated permissions during setup.

Malicious packages are a threat that could happen to anybody, and I hope this story helps you learn more about this problem and how to avoid it.

If you’re into cybersecurity or software development, follow me here on Medium — I publish new articles twice a week.

0
Subscribe to my newsletter

Read articles from Dmitry Protsenko directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Dmitry Protsenko
Dmitry Protsenko