Typosquatting and Slopsquatting: Defending the Package Install Path
Most build failures start with a name. A developer types a package name, a resolver picks the closest match, and a lifecycle script runs with the privileges of the build agent. The attack does not need a vulnerability in your code because it executes during installation, before your code runs at all.
The technique is older than the tooling around it
Publication attacks on open registries are catalogued as supply-chain compromise, and publishing a malicious dependency is a specific sub-technique rather than a generic one. The variants that matter in practice are:
- Typosquatting — a name that is a plausible misspelling or a near neighbour of a popular package.
- Brand substitution — a legitimate-looking name that borrows a vendor prefix or a scope.
- Account takeover — a maintained package receives a malicious version because a maintainer credential was stolen.
- Slopsquatting — a name invented by a code-generation model, registered in advance by someone who guessed the model would suggest it. The first two are cheap to run and cheap to detect. The third and fourth defeat similarity heuristics, which is why registry-side scanning alone has not closed the problem.
Why installation is the dangerous moment
Both major ecosystems execute code at install time. npm runs preinstall, install and postinstall scripts; Python's packaging machinery runs build backends and .pth initialisation. A package that only needs to run once at install time does not require persistence, an exploit, or a second stage that survives a reboot. It needs the install to succeed.
That has a direct consequence for defenders: the network egress of a build agent is part of your attack surface. If a CI runner can reach the public internet on arbitrary ports, then a compromised dependency can reach it too.
What registry and platform signals now exist
Response capability has improved. OpenSSF maintains a curated malicious-packages dataset, and GitHub announced that Dependabot malware alerts draw on it, extending coverage across ecosystems including npm and PyPI. Registry-side scanning on publish adds a second filter. Neither is a guarantee: they detect what has been reported or recognised, and the useful window between a malicious publish and a public report is measured in hours.
Advisory and registry data is therefore a signal to act on, not a substitute for controlling the install path.
Practical controls, ordered by effort
Pin and verify. Commit lockfiles and enforce them in CI. A lockfile with integrity hashes turns a name collision into a resolution failure instead of an install.
Disable install scripts where the project allows it. npm supports ignoring lifecycle scripts (--ignore-scripts) and many dependency trees do not require them. Where they are required, restrict which packages may use them.
Use a proxy registry. A caching proxy with an allowlist gives you a single place to see which names your builds resolve, and a single place to block a name after an incident. It also removes direct registry reachability from build agents.
Separate credentials by scope. A publish token that can write to every package in an organisation converts one stolen CI secret into an organisation-wide compromise. Scope tokens per package and rotate them.
Treat new dependencies as changes. A pull request that adds a dependency deserves the same review as code. Check the repository, the maintainer history, the publish date of the version being pinned, and whether the package's actual contents match its description.
Watch the egress. Alert on build agents making outbound connections to hosts that are not your registries, artefact stores or package mirrors. This catches the class of attack that name-based controls miss.
Responding when a malicious package is confirmed
Speed matters less than order. First, stop the bleeding: remove or block the version at the proxy and revoke any credential the install could have read. Second, determine blast radius from lockfiles and build logs rather than from memory — which agents installed it, on what dates, with which environment variables present. Third, rotate everything those agents could reach, and assume any secret in the build environment was taken. Fourth, look for what the package did after install, not only what it did during install.
What not to conclude
A clean scan is not evidence that a dependency tree is trusted. Registry scanning flags known-bad artefacts, and the interesting cases are the ones nobody has reported yet. Likewise, a package with a long history is not automatically safe; account takeover is precisely the scenario in which reputation is the attacker's asset.
Treat the install path as production infrastructure. It executes code you did not write, with credentials you did provide.
References
- MITRE ATT&CK T1195.002, Compromise Software Supply Chain: https://attack.mitre.org/techniques/T1195/002/
- OpenSSF malicious-packages dataset: https://github.com/ossf/malicious-packages
- Trend Micro, Slopsquatting: When AI Agents Hallucinate Malicious Packages: https://www.trendmicro.com/vinfo/hk/security/news/cybercrime-and-digital-threats/slopsquatting-when-ai-agents-hallucinate-malicious-packages
- Veracode, Application Security in the Cloud (malicious packages and typosquatting): https://www.veracode.com/blog/application-security-in-the-cloud/
- GBHackers, Typosquatted npm Packages Steal Cloud and CI/CD Secrets: https://gbhackers.com/typosquatted-npm-packages/
Top comments (0)