ghostimport

Your AI imported a
package that doesn't exist

Not yet, anyway. The name sits in your repo, unclaimed and public — until someone registers it and your next npm install runs their code. ghostimport checks names against the live registry the moment your agent writes them.

ghostimport
$ ghostimport

  Scanned 142 files · 38 packages

   react-server-fetch  does not exist on npm
     src/data/loader.ts
     unregistered — anyone could claim this name with a malicious postinstall

   axois  high risk
     src/api/client.ts
     1-2 chars from 'axios' — likely a typo
     single version published
    created 2019-08-29 · 1245/week · 1 version

  2 problems found.

How the attack works

A name is a vacant lot until someone builds on it

This is called slopsquatting. It doesn't need a compromised maintainer or a stolen token — only a package name your AI made up and nobody has claimed.

1

Your agent invents a dependency

A language model predicts the most likely next token, not the most accurate one. It writes an import for a package that sounds exactly like it should exist — plausible scope, plausible name, plausible API.

@openai/functions-runtime unregistered
2

The name goes public

You commit. The import is now sitting in a public repository, naming a package that has no owner. Nothing has broken yet — which is exactly the problem, because nothing prompts you to look.

3

Someone claims it

Attackers scrape public repositories for imports that resolve to nothing, then publish those exact names. Registration is free, instant, and requires no interaction with you at all.

@openai/functions-runtime published by ???
4

The install succeeds

This is the part that makes it dangerous. A hallucinated import that breaks your build is a nuisance — you find out in seconds. This one resolves. It downloads. And a postinstall script executes on your machine, and on every machine in your CI.

Where ghostimport cuts in

At step one. It resolves every package name your agent writes or installs against the live registry — before the import is committed, and before the install command runs.

Why your scanner misses it

Audit tools inspect what you installed

npm audit, Snyk and Socket are good at their job. Their job starts once a package is in your lockfile — and a name that doesn't exist yet never gets there.

Agent writes import
Now
Install command
Seconds later
In the lockfile
Committed
Audit / CI
Later
npm audit
known CVEs, installed packages
Snyk · Socket
behaviour of installed packages
ghostimport
does this name exist at all?

Two ways in

Put it where the code gets written

A CI check tells you about a bad package after it's in your repo. These stop it at the moment it appears. Use both — they cover different failure modes.

Enforcing

Agent hooks

Runs on every matching tool call, whether or not the model cooperates. On an install command it denies the call outright.

// .claude/settings.json
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{ "type": "command",
        "command": "ghostimport hook" }]
    }]
  }
}
  • PreToolUse on Bash — vets install commands before they run
  • PostToolUse on edits — checks imports just written
  • Fails open — offline or slow, it exits clean and stays out of your way
Self-service

MCP server

Gives the model the tools to check a name itself, before it commits to writing the import.

# Claude Code
claude mcp add ghostimport \
  -- npx -y ghostimport mcp
  • check_packages — do these names exist?
  • check_install_command — vet a full install line
  • scan_project — audit a whole directory

Works with any MCP client — Cursor, Windsurf, Zed.

What raises a flag

Existing packages get judged too

A name that resolves isn't automatically safe. axois has been on npm since 2019 — one character from axios, one version ever published, and roughly 1,245 installs a week. ghostimport rates it high risk and tells you why; what you do about it is your call.

SignalWeightWhy it matters
postinstall script Critical Runs arbitrary code the moment the package lands
1–2 chars from a popular name Critical The classic typosquat shape
Created < 30 days ago Medium No track record to judge it by
< 50 weekly downloads Medium Nobody else is depending on this
Single version published Medium Abandoned, or published once for a reason
Single maintainer Amplifier Only counts alongside another signal — plenty of good packages have one

Questions

Common questions

What is slopsquatting?

Slopsquatting is when an attacker registers an npm package name that an AI coding tool invented. Language models routinely generate imports for packages that were never published. Those names sit unclaimed in public repositories, so an attacker can publish them and have their code run on any machine that installs the dependency.

Does npm audit catch hallucinated packages?

No. npm audit, Snyk and Socket inspect packages that are already installed and present in your lockfile. A package name that doesn't exist yet never reaches the lockfile, so it falls outside what those tools examine.

How is slopsquatting different from typosquatting?

Typosquatting relies on a human mistyping a real package name. Slopsquatting relies on a model inventing a name that was never real, then an attacker registering it. Typosquatting needs a plausible misspelling; slopsquatting needs only an unclaimed name a model is likely to produce again.

Is an import of a package that doesn't exist actually dangerous?

Not while the name stays unregistered — the install simply fails. The risk is that registration is free and instant. Once someone claims the name, that same install succeeds, and any postinstall script in the package executes on your machine and in your CI.

How do I stop my AI agent from installing a package that doesn't exist?

Run ghostimport as an agent hook. A PreToolUse hook on Bash inspects any install command and denies the tool call when a package doesn't exist, is a typosquat, or ships an install script. Unlike an MCP tool, a hook runs whether or not the model chooses to call it.

Check the name before you trust it

One command. Node 22+. Nothing to configure before it's useful.

$ npm install -g ghostimport
◆ zero runtime dependencies