UrsaKit cover for the guide to verifying packages suggested by AI coding assistants

Ask an AI assistant for a small utility and it will often answer with a confident import and an install command. Sometimes the package does not exist. It is not random noise: the same invented names show up again and again across repeated prompts, which is exactly the property an attacker needs to register a name in advance and wait.

That attack is called slopsquatting, and the defense is not "stop using AI assistants". It is to verify the name before it reaches your package manager, and to make installation harder to weaponize.

01What slopsquatting actually is

The pattern has three parts. A model produces a plausible package name. That name is stable enough to be predictable across users and runs. A registry lets anyone claim an unused name.

Studies of code-generating models have put hallucinated recommendations at roughly one in five of all suggested packages. Duplicate-name typosquatting exploits a human mistyping a known package; slopsquatting exploits a machine confidently inventing one. Because the model presents its suggestion with the same tone it uses for a real library, the mistake is easy to copy into a terminal without a second thought.

Existence is not the same as legitimacy

An attacker can register a hallucinated name after it appears in model output. "npm found it" only proves someone claimed the name — not that the code is safe or that it is what the model meant.

02Why hallucinated names are predictable

Models generate names the way they generate any other token: by continuing the most plausible pattern. For a date library that means concatenating date and a common suffix; for a CLI helper, @scope/tool-name. The output is not the real package, but it looks exactly like one.

Because decoding is guided by the same statistics each time, the same prompt tends to produce the same invented name. That predictability is the vulnerability. It also means the fix cannot be "use a better prompt" — a model that never hallucinates a name is not available, so verification must live in your workflow.

03Verify a name before you install it

Make this a reflex, and the whole class of attack gets much harder.

  1. Ask the registry directly. A 404 ends the conversation.
npm view left-pad version repository.url maintainers time.created
# version = '1.3.0'
# repository.url = 'git+ssh://git@github.com/stevemao/left-pad.git'

npm view left-paad version
# npm error 404 Not Found - GET https://registry.npmjs.org/left-paad - Not found
python3 -m pip index versions requests
# requests (2.32.5)
# Available versions: 2.32.5, 2.32.4, 2.32.3, ...
  1. Match the package to the project you expect. Read repository.url and the maintainer list. A library with a source repository, a changelog and years of releases looks different from a name registered last week with no homepage.
  2. Check the shape of the release history. A package whose entire version list appeared in a single day is a red flag, and so is a wrong-looking version like 99.0.0 chosen to look mature.
  3. Compare the suggestion to what the ecosystem actually uses. If the assistant proposes a wrapper for a well-known library, check whether that library already exposes the feature natively. Hallucinations often exist to fill a gap that does not exist.

04Lockfiles, install scripts and the execution trap

Installing a package is not a read-only action. Lifecycle scripts run on install, and a malicious package can use them to execute code before your tests ever run.

  • Commit and review lockfiles. npm ci installs exactly what the lockfile pins, so a reviewed lockfile is a control. An unreviewed npm install <typo> rewrites it.
  • Skip scripts on first contact. Add a dependency with npm install --ignore-scripts, inspect it, then install normally if you trust it.
  • Use a hash-pinned install for Python. pip install --require-hashes -r requirements.txt refuses a package whose bytes differ from the recorded hash.
  • Keep an install-time review step. A lockfile diff in code review is one of the cheapest places to notice a name that does not belong.
npm ci --ignore-scripts
npm ls --all | head -40
git diff -- package.json package-lock.json

Diff the lockfile, not just package.json

A new top-level dependency often drags in a dozen transitive packages. The lockfile diff shows all of them, and that is where a name you never approved will appear.

05Harden the workflow, not just the moment

Individual checks catch individual mistakes. A few structural controls catch the class.

ControlWhat it stops
Private registry proxy with an allowlistUnknown names never reach developers
Required lockfile reviewSneaked-in transitive dependencies
Disable lifecycle scripts in CIInstall-time code execution
Dependency scanning in CIKnown-malicious packages and CVEs
Internal package naming rulesConfusion between internal and public scopes
Provenance / attestation checksTyposquats without a real build pipeline

The registry proxy is the highest-leverage one: if a package is not already mirrored or allowlisted, the install fails and a human decides. That turns a silent supply-chain risk into a routine review.

06If you already installed the wrong package

Treat it as an incident, not a typo. Remove the dependency, then check what the install actually did: review postinstall and preinstall scripts in node_modules/<name>, look for new outbound network calls, rotate any credentials that were present in the environment during install, and check whether the lockfile was committed and pushed. On a shared repository, the compromised lockfile is the part that spreads.

07Common mistakes and fixes

MistakeWhy it failsFix
Installing straight from the chat answerNo registry check happensRun npm view or pip index versions first
Trusting a package because it existsAttackers register hallucinated namesCheck publisher, repo and release history
Reviewing only package.jsonTransitive packages hide thereReview the lockfile diff
Letting CI run install scriptsMalicious code executes during buildUse --ignore-scripts, or sandbox the install
Assuming a scoped name is internalPublic scopes can look internalEnforce an explicit internal scope

The habit that matters is small: never let a model's suggestion become a dependency without one registry lookup. The rest of the hardening exists for the times you are tired, rushed and ready to trust the output.

Frequently asked questions

What is slopsquatting?

Slopsquatting is registering a package name that an AI model invents, so that the next developer who copies the model's suggestion installs the attacker's code instead of nothing.

Do AI assistants really invent package names?

Yes. Studies of code-generating models found that roughly one in five recommended packages did not exist in the registry, and that the same invented names recur across repeated prompts.

Is it safe if the package exists on npm?

Existence is necessary but not sufficient. A name can exist because an attacker registered it after seeing it hallucinated, so also check the publisher, the repository link, the age and the download pattern.

What is the fastest way to check a package?

Ask the registry directly before installing. For npm that is `npm view <name>`; for Python it is `python -m pip index versions <name>`. A 404 is a stop signal.

Should I disable install scripts?

For untrusted or newly added dependencies, yes. `npm install --ignore-scripts` skips lifecycle scripts, which are a common execution path for malicious packages, then you can install normally once the dependency is reviewed.

Back to articles

Related articles

Related tools