VDB
Sign up

Blog·

We opened 1,332 AI-built repositories. Five of their dependencies do not exist, and anyone can register them.

Most of what is written about slopsquatting measures the model: ask it for code, count how often it names a package that does not exist. We wanted the other end of the pipeline. Of the code people actually built with AI tools and published, how much still depends on a package that is not there?

A dependency that does not exist is not just a broken install. Its name is free, and whoever registers it first decides what that install runs from then on.

What we looked at

Two samples, both taken on 2026-10-03, both with a control group.

Popular projects. Every GitHub repository linked from a Show HN post since January 2025 with more than 20 points: 673 reachable repositories.

Recent, unpopular projects. Repositories created since January 2025 with at most 50 stars, found by the files AI tools leave behind: a Lovable build marker, Bolt's project prompt, a CLAUDE.md, a .cursorrules file. The control group is repositories created in the same period with no such trace.

A repository counts as AI-built if it carries any of these: an agent instruction file (CLAUDE.md, AGENTS.md, .cursorrules and their relatives), commits signed by an AI tool (Co-Authored-By: Claude, Co-authored-by: Copilot and others), a Lovable or Bolt marker, or the author saying so in the Show HN post.

AI-built Control
Popular (Show HN) 412 repositories, 37,158 dependency entries 261 repositories, 7,655 entries
Recent, ≤ 50 stars 920 repositories, 22,966 dependencies added beyond the platform template 303 repositories, 6,494 entries

Every dependency in every package.json, requirements.txt, pyproject.toml, Cargo.toml and go.mod was looked up live in npm, PyPI, crates.io and the Go module proxy — 8,240 distinct names in the first sample and 6,565 in the second.

A side note on the control group: of 600 ordinary repositories we drew from the same period, 297 (49.5%) already carried an AI tool's trace and had to be moved out. Half of new code on GitHub is touched by these tools now.

What we found

A name that is missing from the registry is usually not a phantom. Most were packages that live inside the same repository, private packages under a company scope, packages from a different registry (Deno's JSR, Unity's), or placeholder names in examples. We removed each of those by hand. What was left:

AI-built Control
Popular 1 repository, 1 name 1 repository, 1 name
Recent, ≤ 50 stars 2 repositories, 4 names 0
Names anyone can register today 5 1

The five, without the repositories they are in:

  • Three npm packages in an app built with Bolt, each written as "name": "^1.0.0". None of the three has ever existed on npm, and the app's code imports one of them. The repository's lockfile does not contain them: the install that would have failed was never run, so nothing caught them.
  • A Python package pinned to ==5.3.0 in the backend of an app built with Lovable. The package has never existed, so neither has version 5.3.0. The code imports a hardware library by its module name, and the invented package name is a plausible guess at the real one.
  • A Python package listed in an example's requirements.txt in a popular project. Nothing in the example imports it. It has the name of the application the example is about.

The control group's one is the same shape as the last: a ROS package that is installed with the system package manager, never from PyPI, listed in requirements.txt with an exact version.

Two more were invented but cannot be taken: a @types/ package (only the DefinitelyTyped maintainers can publish under that scope) and a standard-library module (PyPI refuses those names).

What the numbers do and do not say

They say phantom dependencies are rare in published code — about one AI-built repository in four hundred — and that they exist, with version numbers attached, in code people put online.

They do not say AI-built code is worse than other code. Two repositories against none in the unpopular sample and one against one in the popular one are counts too small to compare. The samples come from search rankings, not a random draw.

The repository is the end of the process

A published repository is a finished product. Every phantom package that broke a build on the way there was most likely noticed and removed before anyone pushed: the author ran the app, the install failed, the name went. What we found is what survived, and every case we found survived for the same reason — it sat where nobody ran an install. An example folder. A backend nobody deployed. An app whose lockfile shows its install was never completed.

So these counts are a floor, not a rate. We did not measure what happened before the commit, but two things point the same way. When we put ordinary coding tasks to Claude, GPT and Gemini, they recommended 87 package names that do not exist. Academic work that measures the same thing at generation time (Spracklen et al., 2024) found invented package names in a substantial share of generated code, more for open models than for commercial ones. Between what the model writes and what gets pushed, someone has to catch the rest — usually by running the install and watching it fail.

That makes the dangerous moment the one before the failure. The install fails because nobody has registered the name yet. The day someone does, the same command succeeds, quietly, and runs their code. A phantom name in a published repository is a standing invitation. The three in the Bolt app have been one since March 2025.

Checking at the moment of adding

The place to stop a phantom package is when the agent adds it — before the install that fails today and succeeds once the name is taken. All five names above, sent to VDB's package gate, come back REFUSE:

POST /v1/ai/check-packages
{"packages": ["pkg:pypi/<one of the five>"]}

"agent_action": "REFUSE"
"because":      "this name does not exist on the registry — likely hallucinated, and attackers register such names"

The gate answers up to five packages without a key; see Connect to put it in front of an agent.

How we did it

  • Candidates: Show HN through the Hacker News search API; recent repositories through GitHub search, by the files each tool leaves.
  • AI traces: read from a shallow clone of each repository — the file tree and the last 200 commit messages. No code was run.
  • Dependencies: parsed from the manifests, leaving out workspace, file, git and URL specifiers, aliases (resolved to the real name), the repository's own packages, and scopes its .npmrc sends to a private registry. For Lovable and Bolt, dependencies present in at least half of that platform's repositories count as the template and were left out.
  • Lookups: live, against each registry, with the probe VDB's gate uses.
  • Every flagged name was checked by hand, including the lockfile and the code that would import it.

We told the maintainers of the four repositories involved on 2026-10-03, before this post, and none is named here. We did not register any of the names ourselves.

Comments

No comments yet. Corrections are especially welcome.

    Sign in to comment. No account?Sign up — it is free.