Skip to main content
BlogSecurity

Slopsquatting in 2026: Package Hallucination Rates, 127 Names

A May 2026 re-test of five frontier models found package hallucination rates of 4.62% to 6.10%, yet 127 names were invented by all five. What to gate before install.

Matthews Wong

Software Engineer

October 202612 min read
Slopsquatting in 2026: Package Hallucination Rates, 127 Names

Key Takeaway

Slopsquatting, registering malware under package names that AI models invent, has not gone away. A 2026 re-test of five frontier models measured hallucination rates of 4.62% to 6.10%, down from a 5.2% to 21.7% spread, but 127 names were invented by all five models and 53 were still registrable. Verify existence, age and hashes before any install.

The first thing I did after reading the paper was run its most-hallucinated Python names through PyPI's JSON endpoint. Eight names, eight 404 responses. That is the whole attack in one screen: a package manager command that an assistant will happily write, pointing at a name that nobody owns yet.

This post reads arXiv 2605.17062, a replication of the USENIX Security 2025 slopsquatting study on five 2026 models, closely enough to separate what it measured from what headlines made of it. Every number below comes from that paper, from the original study's page, or from a command I ran on 17 October 2026. The second half is a pre-install gate you can paste into a repository.

The range collapsed, the floor did not move

The original study, by Spracklen and colleagues, generated 576,000 code samples across 16 models and found that at least 5.2% of commercial-model output and 21.7% of open-source output named a package that does not exist. The replication, by independent researcher Aleksandr Churilov, re-ran the same prompt datasets against five models released between October 2025 and March 2026: 199,845 generations, each package validated against PyPI and npm name lists. Overall rates landed between 4.62% for Claude Haiku 4.5 and 6.10% for GPT-5.4-mini.

Read that as a narrower spread, not a safer floor. The gap between best and worst fell from 16.5 percentage points to 1.48, mostly because the open-weight model in the cohort, DeepSeek V3.2, no longer lags the commercial ones. But the paper's own chart notes that no 2026 model beat the best 2024 result, 3.6% for GPT-4 Turbo. The bad tail disappeared; the good end did not improve.

Per-model hallucination rate by language, in percent, from Table 2 of the replication.

ModelPythonJavaScriptOverall
Claude Haiku 4.55.492.764.62
Claude Sonnet 4.66.632.625.41
Gemini 2.5 Pro6.753.615.80
DeepSeek V3.26.693.785.89
GPT-5.4-mini7.273.146.10

The language split is the surprise. Every model hallucinated more in Python than in JavaScript, by 2.73 to 4.13 percentage points, which reverses the 2024 finding that npm was the noisier ecosystem. The authors' guess is that Python names have more ways to be plausible and wrong: aws-cdk, aws_cdk and aws-cdk-lib all exist with different meanings. They flag that as a hypothesis, not a result.

What the number measures, and what it does not

The method is deliberately old. One sample per prompt, default sampling settings, regex extraction of pip install, npm install, import and require lines, and a name counts as hallucinated only if it is absent from the master lists shipped with the 2025 artifact. Refusals and unparseable replies are excluded from the denominator, so a model that declines more often can look better or worse than it behaves.

The authors list limits that matter if you are deciding how much to trust 4.62%. GPT-5.4-mini was run at minimal reasoning effort and refused 32.14% of prompts, so its rate sits on a lopsided denominator. The deepseek-chat alias returned the identifier deepseek-v4-flash in response metadata during the run, so the V3.2 label is a caveat. The prompt corpus has been public since January 2025 and may have leaked into training data, which would bias rates downward. And no agentic setup with tool use or retrieval was tested, where a model can look a name up before writing it.

That last gap is the one I would watch. If your assistant checks a registry before it suggests an install, this paper's rate does not describe you. If it answers from memory in a chat window, it does.

127 names every model invents, and 53 an attacker could take

The paper's most useful contribution is an intersection. Taking only names that all five models hallucinated, after a noise filter, leaves 127: 109 on PyPI and 18 on npm. The authors disclosed the full list to PyPI Security and to Socket.dev on 29 April 2026. PyPI's prohibited-name and normalisation rules leave 41 of the 109 registrable. Socket's review removed six of the 18 npm names, which leaves 12. That is 53 names, 41 plus 12, that one attacker could register once and reach users of every provider.

Invented name (PyPI)Count across modelsWhat the model probably meant
aws-cdk429the real package is aws-cdk-lib
objc375the real package is pyobjc
opentelemetry374real packages are opentelemetry-api and opentelemetry-sdk
rest-framework315the real package is djangorestframework
tencentcloud215the real package is tencentcloud-sdk-python

Two mechanisms explain why different models agree on a wrong answer. Tutorials and blog posts that misname a package, such as using rest_framework as if it were the install name, become a shared training signal. And models over-apply naming conventions, like npm scopes, to things that are not published as standalone packages: the four @ember names were universal hallucinations but sit in a scope only Ember controls, which is why Socket marked them non-exploitable. The paper also notes that of the top Python names, many are within edit distance 2 of a real package, so a typo-squat that already exists can catch the same mistake.

Why 4 to 7 percent is still an economic attack

The paper's own arithmetic is blunt. At the lowest observed rate, a 39,969-prompt sweep per model yields more than 1,300 hallucinated mentions, mapping to several hundred unique names. Uploading to PyPI or npm costs nothing, and the authors put the API spend for their full five-model sweep at 860.90 USD. For an attacker the break-even is far below 1%, so the threat does not depend on the rate being high.

Two of their findings make it worse for defenders. Synthetic prompts, generated by another model, produced more hallucinations than curated Stack Overflow questions, so an attacker who builds a prompt pool to maximise harvest will out-collect a survey that uses organic questions. And the cost of a universal name is one registration while its reach is the union of every provider's users.

The failure: treating a falling rate as a falling risk

The mistake I see in how this result gets repeated is arithmetic of the wrong kind. Per-model rates fell, so people conclude the exposure fell. Exposure is the number of registrable names an assistant will confidently emit, multiplied by how many installs follow without a human reading them. The first term is 53 and not zero; the second term grew over the same eighteen months as agents began running installs themselves.

A 404 on a package name is not a clean bill of health, and a 200 is not one either. The authors say the 53 figure is a point-in-time estimate against April 2026 registry state, and that some names are now real packages. A name that exists today may have been registered last week by someone who read the same paper. Check existence and age together.

I ran the check myself on 17 October 2026 against eight PyPI names from the paper's most-hallucinated table: aws-cdk, objc, opentelemetry, rest-framework, tencentcloud, mpl-toolkits, opengl and openstack. PyPI's JSON endpoint returned 404 for all eight. I cannot tell you from that whether each is registrable, since PyPI blocks some names by rule. The result tells me only that the commands these models write for those names still fail to resolve, which is the safe outcome and one fresh registration away from not being.

A pre-install gate: existence, age, hashes

Three cheap controls stack well. First, refuse any dependency the registry does not know or only learned about recently. PyPI's JSON API returns an upload time per file, so first-upload age is a single request. Second, pin with hashes so that an install fetches only artifacts a human already resolved. pip's hash-checking mode is all-or-nothing: once one requirement has a hash every requirement needs one, and each must be pinned with == or a URL. Third, give resolvers a cooling-off period. uv's exclude-newer accepts durations such as 7 days or an RFC 3339 timestamp, and compares against each file's upload time.

Here is the check I wrote for the first control. It is stdlib Python, treats a missing project as a block, and blocks anything whose earliest file is under 30 days old. The 30 is my choice, not the paper's; tune it to your tolerance.

# check_pypi_first_upload.py - run on names an assistant proposes,
# BEFORE they reach requirements.txt. Standard library only.
import json, sys, urllib.request, urllib.error
from datetime import datetime, timezone

MIN_AGE_DAYS = 30

def first_upload(name):
    url = f"https://pypi.org/pypi/{name}/json"
    try:
        with urllib.request.urlopen(url, timeout=15) as r:
            data = json.load(r)
    except urllib.error.HTTPError as e:
        if e.code == 404:
            return None
        raise
    times = [
        f["upload_time_iso_8601"]
        for files in data["releases"].values()
        for f in files
    ]
    return min(datetime.fromisoformat(t.replace("Z", "+00:00")) for t in times)

for name in sys.argv[1:]:
    first = first_upload(name)
    if first is None:
        print(f"BLOCK  {name}: not on PyPI (hallucinated?)")
        continue
    age = (datetime.now(timezone.utc) - first).days
    verdict = "BLOCK" if age < MIN_AGE_DAYS else "ok   "
    print(f"{verdict}  {name}: first upload {first:%Y-%m-%d}, {age} days old")

Run it against the names an assistant proposes before they reach a requirements file, not after. The other two controls live in the files below.

# requirements.in  (human-reviewed, loose)
httpx>=0.27

# Resolve once, with hashes (pip-compile comes from the pip-tools package). Every transitive dependency is pinned with ==
# and gets sha256 lines, which is what hash-checking mode demands.
pip-compile --generate-hashes -o requirements.txt requirements.in

# Deploy: --require-hashes turns "a dependency has no hash" into an error.
# Without it, hash checking only switches on if some line happens to carry one.
pip install --require-hashes -r requirements.txt

# pyproject.toml - uv: ignore any file uploaded in the last week.
# uv compares against each file's upload time, not the version's release date.
[tool.uv]
exclude-newer = "7 days"
# Per-package override, or false to exempt a package from the global cutoff:
# exclude-newer-package = { internal-tool = false }

Note what the cooling-off setting cannot do. It filters by upload time, so it keeps out a package registered yesterday, but a squatter who registered a hallucinated name months ago and waited gets through. That is a limit of the control, which is why hashes and review stay in the stack.

What each control stops, and what it misses

ControlStopsMisses
Existence and first-upload checkNames that do not exist, and names registered in the last few weeksA squat registered long ago, and a legitimate name taken over later
pip --require-hashesSilent substitution after you resolved the lock; a changed artifactA malicious package you hashed yourself on the day you first added it
uv exclude-newerFreshly uploaded releases reaching a resolverAnything uploaded before the cutoff, including old squats
Human review of every new dependencyThe model-agnostic names, because a person asks why this package existsReviewer fatigue when an agent adds dependencies in volume
Agent with registry lookup before installMemory-only guessing, the setting the paper measuredNot measured by this paper; the authors list it as future work

The cheapest high-value review rule is a diff rule: any pull request that adds a name to a lock or requirements file gets a required reviewer. The paper's top invented names look plausible on sight, which is exactly why they work.

What to do on Monday

None of this needs a platform team. Start with where assistants write install commands for you, and work outward.

  1. Add the existence and age check to your pre-commit or CI step for requirements and package.json changes, and fail on a missing or very new name.
  2. Move Python deploys to hashed requirements and add --require-hashes so an unhashed dependency is an error rather than a surprise.
  3. Set exclude-newer in uv projects to a short window such as 7 days, and exempt specific packages per project with exclude-newer-package only where you have a reason.
  4. Tell your team that an install command from a chat window is a suggestion. Agents that run installs unattended should resolve names against a registry first.
  5. Re-run the existence check on your lock files quarterly, because the 53 figure is a snapshot and the registries move.

The rule I carry away: judge slopsquatting by the names, not the rate. A model that is wrong 5% of the time is wrong in the same places as its competitors, which turns a statistical nuisance into a short, enumerable list an attacker can register once. Gate on existence, age and hashes, and treat the paper's 53 as a floor on what exists.

FAQ

Frequently Asked Questions

Short answers to what readers ask most about this topic.

What is slopsquatting?

Slopsquatting is the registration of malicious packages under names that AI models hallucinate. A developer or agent runs an install command an assistant wrote, and the package manager fetches the attacker's package. The term comes from the research that the USENIX Security 2025 paper by Spracklen and colleagues measured.

How often do AI models hallucinate package names in 2026?

In an arXiv replication run in April 2026 on five frontier models, overall rates ranged from 4.62% for Claude Haiku 4.5 to 6.10% for GPT-5.4-mini. The earlier study reported 5.2% for commercial and 21.7% for open-source models. The authors note limits, including refusal-rate differences and no agentic testing.

What are universal hallucination names?

They are package names that all five tested models invented identically: 127 in total, 109 on PyPI and 18 on npm. After disclosure to PyPI Security and Socket.dev, 53 remained registrable. One registration of such a name could reach users of every provider at once.

Does a lower hallucination rate mean I can stop checking dependencies?

No. At 4 to 7 percent an attacker still collects hundreds of unique names cheaply, and uploading to PyPI or npm is free. The paper stresses that the threat does not depend on a high rate. Keep existence, age and hash checks, plus human review of new dependencies.

How can I check whether an AI-suggested package is safe to install?

Confirm that the name exists on the registry, check when its first file was uploaded, and read who maintains it. Then pin with hashes using pip's require-hashes mode and set a cooling-off window such as uv's exclude-newer. None of these alone proves a package is benign, so review new additions.