Is the npm package your AI agent added safe?
An agent can add an npm name that does not exist yet, which an attacker can register later, or a real package whose install script runs with your tokens.
By ShipSecurely Editorial · Updated · How we make these guides
Shows up in: Next.js, Vercel, GitHub
What it is
An AI coding agent can hand you a package name that is not on npm. Anyone can register that name afterward. People call that slopsquatting. Andrew Nesbitt writes that Seth Larson suggested the name in April 2025. The USENIX Security 2025 paper by Spracklen et al., "We Have a Package for You!", calls the same behavior package hallucination. The paper's adversary model is a model that recommends a missing name, and an attacker who then publishes that name so a later install gets the attacker's code.
The other failure is a real package. It can be malicious from the first publish, or a compromised version of a package you already trust. CERT-In advisory CIAD-2025-0034 says the Shai-Hulud campaign's malicious versions ran a postinstall script. That script runs on the machine or build server doing the install, in an environment that can hold GitHub tokens and cloud API keys. A known-vulnerability audit is a different check. See Outdated dependencies and npm audit.
Treat a new name from an agent as untrusted until you have looked it up. "Is this npm package safe" is a question about the registry record, the repository, and the install scripts, not a question the model can answer by sounding sure.
What the research found
Spracklen, Wijewickrama, Sakib, Maiti, Viswanath, and Jadliwala published "We Have a Package for You! A Comprehensive Analysis of Package Hallucinations by Code Generating LLMs" at the 34th USENIX Security Symposium in 2025. The results section says they ran 30 tests, using 16 models for Python and 14 models for JavaScript, and produced 576,000 code samples. Those tests recommended 2.23 million packages. Of those recommendations, 440,445 (19.7%) were hallucinations, covering 205,474 unique names that were not in PyPI or npm.
The abstract says the average percentage of hallucinated packages is at least 5.2% for commercial models and 21.7% for open-source models. The results section attributes that 5.2% to the GPT series, against 21.7% for the open-source models. Python code hallucinated less than JavaScript: 15.8% on average, against 21.3% for JavaScript. These are the paper's numbers for the models and prompts it tested. They are not a rate for any coding agent today.
The paper also measured how close hallucinated Python names were to a real package. In that test, 13.4% (10,263 of 76,489) were a Levenshtein distance of 1 or 2 from the nearest valid name, which the paper defines as an off-by-one error of one or two characters. The paper's conclusion from that distribution is that most of those names are not simple typos.
What a malicious install does
CISA's alert of September 23, 2025, "Widespread Supply Chain Compromise Impacting npm Ecosystem," describes a self-replicating worm publicly known as Shai-Hulud. CISA says it compromised over 500 packages. After initial access, the actor's malware scanned the environment for credentials. It targeted GitHub personal access tokens and API keys for Amazon Web Services, Google Cloud Platform, and Microsoft Azure. CISA says the malware then exfiltrated those credentials to an endpoint the actor controlled, uploaded them to a public repository named Shai-Hulud through the GitHub/user/repos API, and spread by authenticating to the npm registry as the compromised developer, injecting code into other packages, and publishing compromised versions.
CISA's recommendations in that alert are to review dependencies across software that uses npm, check package-lock.json or yarn.lock for affected packages including nested ones, and search cached copies in artifact repositories and dependency tools. Pin npm dependencies to known safe releases produced prior to September 16, 2025. Rotate all developer credentials. Mandate phishing-resistant multifactor authentication on developer accounts, especially GitHub and npm. Monitor for unusual network traffic, block outbound connections to webhook.site domains, and watch firewall logs for suspicious domains. On GitHub, remove unnecessary GitHub Apps and OAuth applications, audit repository webhooks and secrets, enable branch protection, and enable secret scanning alerts and Dependabot security updates.
CISA's alert does not describe how the package code started. CERT-In advisory CIAD-2025-0034, issued September 25, 2025, says malicious versions in this campaign contain a worm that executes a post-installation (postinstall) script. That advisory says the script scans for .npmrc npm tokens, environment variables, GitHub personal access tokens, and cloud API keys for AWS, GCP, and Azure, then publishes further tainted versions with the compromised developer's npm credentials. CERT-In also says to look for unauthorized repositories named "Shai-Hulud," a workflow at .github/workflows/shai-hulud-workflow.yml, and unexpected branches named shai-hulud.
How to check in 5 minutes
After every agent session, run
git diffonpackage.jsonand the lockfile (package-lock.json,pnpm-lock.yaml, oryarn.lock). A name you did not ask for is the stop.For each new name, run
npm view NAME time.created repository.url, with NAME replaced by that package. The npm view docs say child fields are separated with a period, andrepository.urlis the documented field for the git URL. A package whosetime.createdis a few days ago and whose repository is empty, or a name one letter off a package you already use, is a stop.Check new packages for install scripts. On npm 12,
npm install-scripts lslists dependency install scripts thatallowScriptsdoes not cover yet. On older npm,npm view NAME scriptsprints the scripts field. Read anypreinstall,install, orpostinstall.Turn on Dependabot malware alerts. In the repository, open Settings, then Advanced Security, enable Dependabot alerts, then enable Dependabot malware alerts. GitHub lists malware alerts with the security features available on all plans, without buying GitHub Code Security.
How to fix
npm
npm 12.0.0, released July 8, 2026, says dependency lifecycle scripts are blocked by default unless the root package's allowScripts policy allows them. The v12 npm install-scripts docs say the same thing: install commands skip lifecycle scripts for a dependency with no matching allowScripts entry, and they list what they skipped. npm install-scripts approve PKG records the approval in allowScripts in package.json. PKG is the package name. The allow-scripts-pin config defaults to true, so the command writes a version-pinned entry (pkg@1.2.3). The 12.0.0 notes say to run npm rebuild afterward if you want the newly approved scripts to execute.
GitHub's June 9, 2026 changelog says npm 11.16.0 and newer still run those scripts and print a warning, and that the block is the v12 change. The v11 npm install-scripts page, fetched on October 19, 2026, uses the sentence "Dependency install scripts are blocked by default." That page and the June changelog do not agree. Run npm --version. If it is not 12, do not assume a script was skipped. ignore-scripts=true is the blunt option on the versions that still run scripts: the config docs say npm then does not run scripts specified in package.json files. Commands such as npm test and npm run still run the script you named, and they skip pre- and post-scripts.
--dangerously-allow-all-scripts is a real flag. The v12 config docs say it bypasses allowScripts and runs every dependency install script, and that it is a migration escape hatch whose use is strongly discouraged. Do not set it to make an install pass.
npm 11.10.0, released February 11, 2026, added min-release-age. The v11 and v12 config docs say it is a number of days: only versions published more than that many days ago are installed. Set it in .npmrc as min-release-age=7. min-release-age-exclude is a list of names or glob patterns that skip the window. If before and min-release-age are both set in the same config source, before wins. The documented trade-off is the same in those docs: when the window stops npm audit fix from installing a patched version because the fix is too new, npm keeps the vulnerable version, warns that the fix was blocked, and exits with a non-zero code.
In CI, commit the lockfile and install with npm ci. The v12 npm ci docs say the command is for automated environments, requires package-lock.json, exits with an error if the lockfile does not match package.json, and does not write to either file.
pnpm
pnpm's v10 settings say that since v10, lifecycle scripts of dependencies do not run unless the package is listed in onlyBuiltDependencies. The v11.0 release notes say allowBuilds replaces onlyBuiltDependencies and the other legacy build-dependency settings. The current supply-chain page says v10 disables automatic execution of postinstall scripts in dependencies and recommends listing trusted dependencies in allowBuilds.
minimumReleaseAge was added in v10.16.0. The v10 settings page types it as a number of minutes and defaults it to 0. The same page says: "In most cases, malicious releases are discovered and removed from the registry within an hour." That is pnpm's claim. The v11.0 release notes change the default to 1440 (1 day) and say to set minimumReleaseAge: 0 in pnpm-workspace.yaml to opt out. The v10 settings page is titled for pnpm-workspace.yaml.
Vercel
Vercel runs an install command as part of the build. The builds docs say the install command is set with the build command, and the fundamentals guide says the build installs dependencies by detecting the lockfile and respecting it. Commit the lockfile so that install has one to respect.
The builds docs say Vercel injects project environment variables, including API keys, during the build, and that those variables stay inside the build environment. Vercel's Node.js docs say to put an npm token in a project environment variable named NPM_TOKEN (or the contents of an .npmrc in NPM_RC) so private modules can install. A token you place there is available to that install. Prefer to keep other long-lived secrets out of build environment variables. If a malicious version was installed in a build, rotate the credentials that build could see. CISA's alert says to rotate all developer credentials. A token that reached git is the separate problem in Keys committed to GitHub.
GitHub
Dependabot malware alerts fire when a package on the repository's default branch is flagged as malicious. Alerts for dependencies you already have are generated once the package is flagged in the GitHub Advisory Database, and also when you push a commit that adds a known malicious package or moves one to a known malicious version. The limitations on that page say only advisories reviewed by GitHub trigger alerts, and that new malware can take time to appear in the database and trigger an alert. Alerts do not catch every issue. Keep the manifest and the lockfile current so the scan sees what you installed.
The GitHub changelog of July 28, 2026 says the GitHub Advisory Database now ingests malware advisories from the OpenSSF malicious-packages repository, and that you can view them with the type:malware filter. The advisory database docs say the same filter. Browse type:malware there when you want the advisory itself rather than the alert on your repo.
Socket looks at dependency behavior. OSV-Scanner matches lockfiles to known vulnerabilities in the OSV database. Neither one replaces reading the diff of a name an agent just added.
Copy the fix prompt
Paste this into Cursor, Lovable, Bolt, or Claude Code. Read the diff before you merge it.
You are adding or reviewing dependencies. Do not add features. 1. Never add a dependency without listing the name and saying why it is needed. 2. Prefer a language built-in or a package already in package.json. 3. Before adding a package, confirm it exists on npm. Show me the repository URL and the first publish date from `npm view NAME time.created repository.url`. 4. Never run npm install with --dangerously-allow-all-scripts. Never approve an install script unless you tell me the package name, the version, and the script you read. 5. Do not edit .npmrc or allowScripts to make an install pass. 6. If a name does not resolve on npm, stop and ask me. Do not invent a replacement and install it. End with the packages you added, the packages you refused, and any install script you want me to approve.
Questions
Does npm audit catch this?
npm audit sends the dependencies in your project to the registry and asks for a report of known vulnerabilities. A brand-new package, or a compromised version that has no advisory yet, is absent from that report. Read the report for the vulnerabilities it does list, and still check new names and install scripts. OSV-Scanner is the same kind of check against the OSV database.
Is a typo-squat the same as a hallucinated package?
A typo-squat is a published name a character or two away from a package people already install. A hallucinated package is a name a model recommended that was not in the registry. The USENIX paper calls that package hallucination. In its test of hallucinated Python names, 13.4% (10,263 of 76,489) were one or two characters from the nearest valid name, and the paper says most of those names are not simple off-by-one errors. Either kind is a reason to stop: look up time.created and repository.url before you install.
My agent installed something weird. What now?
Remove the name from package.json, delete node_modules, and reinstall from a lockfile you trust with npm ci or the pnpm equivalent. If an install script ran on your machine or in a Vercel build, rotate the tokens that environment had. CISA's Shai-Hulud alert says to rotate all developer credentials, mandate phishing-resistant MFA on GitHub and npm, and audit GitHub Apps, OAuth applications, repository webhooks, and secrets. CERT-In's advisory for that campaign also says to look for a public repository named Shai-Hulud, .github/workflows/shai-hulud-workflow.yml, and a branch named shai-hulud. For that alert specifically, CISA says to pin npm dependencies to known safe releases produced prior to September 16, 2025.
Sources
- Spracklen et al., USENIX Security 2025, "We Have a Package for You!"
- Spracklen et al. paper (PDF)
- CISA alert, September 23, 2025: Widespread Supply Chain Compromise Impacting npm Ecosystem
- CERT-In advisory CIAD-2025-0034
- Andrew Nesbitt, "Slopsquatting meets Dependency Confusion"
- npm config (v12)
- npm config (v11)
- npm install-scripts (v12)
- npm install-scripts (v11)
- npm ci (v12)
- npm view (v11)
- npm audit (v11)
- npm CLI v11.10.0
- npm CLI v12.0.0
- GitHub changelog, June 9, 2026: upcoming npm v12 breaking changes
- pnpm: mitigating supply chain attacks
- pnpm v10 settings
- pnpm 11.0 release notes
- Dependabot malware alerts
- Configuring Dependabot malware alerts
- GitHub security features
- GitHub Advisory Database
- GitHub changelog, July 28, 2026: Dependabot alerts on malicious packages across more ecosystems
- How Vercel builds your application
- Vercel builds
- Configuring a Vercel build
- Vercel advanced Node.js usage, including private npm modules
Related
Guides
Incidents
- Node.js fixed a Brotli decoder bug that can run code, and Vercel says Node 20 projects must move to 22 or 24
- @sentry/nextjs tunnelRoute skipped Next.js middleware for more paths than it forwards to Sentry
- An encoded URL could skip Next.js middleware and get a protected page from the OpenNext Cloudflare cache
Need someone to fix it for you? See /help.
The weekly fix
The weekly fix: 3 real security mistakes in vibe-coded apps and how to fix them, every Tuesday.