Field report

404 repositories imported a package nobody owned

I scanned 174 public GitHub repositories looking for npm imports that AI tools made up. I didn't find any. What I did find was a package name that Lovable's project template had put into 404 public repos, and nobody had ever published it on npm. I reported it to Lovable, and they reserved the name 16 days later.

Method

How I picked the repos

If made-up imports are an AI problem, they should show up more often in projects built with AI. So I scanned two groups: popular JavaScript and TypeScript projects as a baseline, and recent repos whose README says they were built with an AI tool.

GroupHow they were chosenReposFiles
Established Over 5,000 stars, JS or TS, e.g. axios, redux, date-fns, react-hook-form, socket.io 4710,894
AI-assisted Created after 2025-06, README says “vibe coded”, “built with Lovable” or “built with Cursor” 12712,879

For each repo I downloaded the tarball from the GitHub API, ran ghostimport --json on it, and deleted it. Then I looked up every flagged name on the npm registry by hand. That manual check ended up mattering most, because a lot of what the tool flagged was wrong. More on that in Finding 03.

I only used public data: repo tarballs and code search through the GitHub API, and the public npm registry. I didn't run code from any of these repos, didn't register any package names, and the only project I contacted was Lovable, through their official disclosure program.

Finding 01

No made-up imports reached a public repo

0
Organic hallucinations
Across all 174 repos, in both groups.
4,555
Unique imports checked
All but three were on npm, were local code, or were fake on purpose in tests.

Honestly, this surprised me, and it undercuts how I had been pitching ghostimport. It makes sense, though. If an AI invents a package name, npm install fails the first time anyone runs it. Somebody notices, fixes it, and only then commits. By the time the code is on GitHub, the mistake is long gone.

So scanning finished repos is the wrong place to look. The risky moment is between the agent writing the import and someone running the install. That's why ghostimport also runs as an MCP server and as an agent hook, and not only as a command-line scanner.

A false alarm I nearly reported

My first pass turned up @anthropic/sdk, @openai/api and @langchain/agents. They look exactly like names a model would invent, and none of them exist on npm. All three came from one repo: another open-source tool in this space, which keeps fake package names in its test suite on purpose. After that, I opened every flagged file before counting anything.

Finding 02

One template, 404 repos, and a package name nobody had registered

404
Distinct public repos
Imported the name when I scanned: 657 file matches, the full result set.
16
Days from report to fix
Lovable reserved the name on 2026-09-15.

The name was lovable-agent-playwright-config. It showed up in two files, playwright.config.ts and playwright-fixture.ts, and those files looked almost the same in projects that had nothing else in common. They come from the template Lovable uses when it generates a project.

When I scanned, nobody had ever published that package on npm. GitHub code search found it in 657 files across 404 public repos, always in one of those two files, either at the root or inside frontend/ or client/. Code search doesn't cover private repos, so the real number was higher.

Why it mattered

A made-up import in one person's code just breaks their build. A made-up import in a template gets copied into every project the template creates. This one also started with lovable-, so it would have looked legitimate to anyone reading it. If a stranger had registered the name first, installing it, which is exactly what a developer or an AI agent does to fix a missing import, would have run their code. npm runs a package's postinstall script automatically.

Reporting it

DateWhat happened
2026-08-30Found it in the scan and reported it privately to Lovable through their disclosure program on HackerOne
2026-09-13Published this report, leaving out anything that identified the issue
2026-09-15Lovable registered the name as an empty placeholder and marked the report resolved

The package is now an empty placeholder owned by Lovable, with just a README and no install scripts, so nobody else can take the name. I never registered it myself.

Thanks to the Lovable security team for fixing it. They also credited the report on their HackerOne thanks page.

check it yourself
$ npm view lovable-agent-playwright-config version description time.created
version = '0.0.0'
description = 'This package is not intended for use.'
time.created = '2026-09-15T10:10:18.192Z'

Not every unpublished name can be taken

Two other unpublished names in the scan were scoped packages, used by example projects in the same repo. Those were never at risk: the scope already has an owner on npm, and only the owner can publish packages under it.

ghostimport 0.5.2 got this wrong and flagged both as free to register. Since 0.6.0 it checks whether a scope has an owner before saying that.

Finding 03

Most of the bugs were in my own tool

This was the first time I had run ghostimport on a lot of real code, and it didn't go well. Version 0.5.1 flagged a missing package in almost one in five popular repos, and nearly all of those were false alarms. A security tool that noisy just gets switched off.

Measurev0.5.1v0.5.2
Established repos with a flagged package19.1%12.8%
AI-assisted repos with a flagged package11.8%5.5%
Distinct wrong names flagged5525

I traced the false alarms to six bugs, all fixed in 0.5.2:

BugWhat went wrong
Root-only configNested package.json and tsconfig.json files in monorepos were ignored, so workspace packages looked missing
Scoped aliasesThe alias @commands was compared against the full import @commands/types, so it never matched
Comment strippingThe JSONC parser removed https:// inside strings, which broke every Deno import map it read
Framework scopes@theme/* and @site/* are handled by Docusaurus and @std/* by Deno, and none of them come from npm
Build outputFolders like .vercel were scanned, so bundled code looked like real imports
Non-JS filesshared.dart was read as a package name, because dots are allowed in npm names

About two thirds of what still gets flagged is fake names in test fixtures, in projects that test import parsing. I decided not to skip test folders. AI agents write tests too, and a made-up import in a test file is still a made-up import.

Scan log

Every scan behind these numbers

Each run, with the date and the tool version, so you can see where the figures above come from.

DateCorpusVersionResult
2026-08-30 174 repos · 23,773 files v0.5.2 25 names flagged · 3 confirmed unpublished · 1 that anyone could have registered, now reserved by Lovable · 0 organic hallucinations
2026-08-29 174 repos · 24,414 files v0.5.1 55 names flagged · 30 false alarms traced to 6 bugs

Try it yourself

You don't need my data. Run the scanner on any repo and look up the names it flags on npm.

reproduce
$ npx ghostimport@0.5.2 ./some-repo --json
$ npm view <name-it-flagged>   # a 404 means nobody has published it

If you maintain a template, check its imports

Confirming the Lovable name took one command, and so did fixing it. Starter templates, scaffolding tools and docs examples all put package names into other people's code. If one of those names isn't registered, anyone can register it. Checking takes a minute.