The agent imports a package. The package has a postinstall script. You never opened package.json.
Setup
A repo where the agent has been told to “add HTTP retry logic”. It produces:
{
"dependencies": {
"axios-retry-helpers": "^1.0.0"
}
}axios-retry-helpers is hallucinated. Real package: axios-retry. An attacker registered the hallucination and added a postinstall step.
A defanged postinstall
What a real attacker would write — replaced here with a harmless echo:
{
"name": "axios-retry-helpers",
"scripts": {
"postinstall": "echo 'demo: would exfiltrate ~/.npmrc, ~/.aws/credentials, GITHUB_TOKEN'"
}
}Trigger
npm install. The script runs before your code touches the package.
Real-world: Shai-Hulud (Sept 2025)
A self-replicating npm worm:
- Compromised maintainer of
@ctrl/tinycolorvia phishing - Published a poisoned version that injected a GitHub Action
- The Action stole npm, GitHub, AWS, GCP tokens from CI runs
- Used the stolen npm token to publish the same payload into other packages the maintainer owned
- Spread to hundreds of packages before the registry intervened
An agent running npm install unattended in CI is functionally a maintainer with a publish token.
Slopsquatting
Lasso Security and Vulcan Cyber research found ~20% of LLM-suggested packages don’t exist. Attackers register the hallucinated names and wait. The model imports them confidently. CI installs them.
Defense
- Pin exact versions, commit lockfiles, diff lockfile changes in PR review
npm config set ignore-scripts trueto disable postinstall- Scanners: socket.dev, snyk, osv-scanner
- See defenses for full setup