Typosquatting bets on your typo. Slopsquatting bets on your AI assistant. When a model invents a package that doesn't exist, an attacker registers ...
Some comments have been hidden by the post's author - find out more
For further actions, you may consider blocking this person and/or reporting abuse
Great overview. One thing I'd add is that the biggest risk isn't just developers copy pasting AI generated commands anymore. It's AI agents that can automatically resolve and install dependencies. That makes package verification and allowlists much more important than before. I think this shift deserves more attention because the attack surface is growing beyond human mistakes.
Good point, and it makes the chain shorter rather than longer. With an agent doing the install there is no step where a human looks at the name and thinks twice, so the only control left is the one that does not depend on anyone noticing. That is exactly why the allowlist proxy matters more than developer discipline here.
I'm curious if you think package registries could do more here. For example, should npm or PyPI flag newly published packages that suddenly match common AI hallucinations, or would that create too many false positives? It feels like registries could become part of the defense instead of putting all the responsibility on developers.
They could and some of it is already happening! npm v12 turns off install scripts by default and pnpm added a 24 hour minimum release age which both take away the fast trigger without needing to guess intent. The tricky part with matching against known hallucinations is that the list of stable fake names is also the attacker's target list. so publishing it hands them the reconnaissance. and surfacing signals like package age missing repo and first ever release at install time feels safer than trying to block on a name.
That makes sense. Focusing on package reputation instead of package names feels like a better long term approach. It also scales better since attackers can always register a different hallucinated name, but trust signals are much harder to fake.
and also one thing that could make it even stronger is including a real example of a hallucinated package that was later registered by an attacker. Seeing the attack flow from AI suggestion to malicious install would make the risk much more tangible for readers.
Thanks for the great article. I like how you explained slopsquatting in a simple and practical way without making it feel overcomplicated. It is a good reminder that AI generated code still needs the same level of verification as any other external dependency. Really enjoyed the read and learned something new.
Thanks, glad it landed. That verification point is really the whole thing: a package name from a model is a suggestion, not a citation, and a quick npm view or a look at the release history kills most of these before they ever reach your machine.
Good point about not turning hallucinated names into a target list. I could also see IDEs and AI coding assistants using those trust signals before suggesting or installing dependencies. That would catch a lot of cases before they ever reach the package manager.
Agreed, that is the right place for it, since the assistant is where the name is born,right
The repeating-hallucination finding is what makes this operationally serious rather than theoretically interesting. If every fake package name were unique, registering them would be noise. But if the same model reliably suggests
requests-oauth2-helperacross thousands of queries, an attacker only needs to register it once. We already have this problem in static analysis: rules that detect package imports don't help if the package name itself is the vector — the import looks syntactically clean. Running something likenpm queryor a lockfile audit post-install catches it after the fact, but the install already ran. I've been thinking about whether pre-install hooks that validate package existence against the registry could be standardized in toolchains — feels like something that belongs in the resolver layer, not bolted on top.Thanks Ofri, the resolver layer is where I keep landing too. The catch with a plain existence check is that slopsquatting defeats it by design, since the attacker registers the name first and the package really is there when you look. What helps more at resolve time is trust metadata instead of presence, things like first publish date, dependents and maintainer age, and a few package managers are already halfway there with a minimum release age setting.
I'll keep this in mind when I begin to use AI agents more throughout my coding in the future. This is the first time I've seen AI hallucinations being weaponized like this, and the scariest part is that this can be a silent attack if a package was made just the other day; I'd have to stay on my toes every time an agent suggests a package I've never heard of or am unfamiliar with.
The
pip index versionstip is going to be a lifesaver. Thank you, I learned something new!Glad it was useful! One thing that might take some pressure off: you do not have to be vigilant on every single suggestion, since most of the damage comes from install scripts running automatically. Turn those off once and an unfamiliar package sitting in your tree is much less dangerous while you check whether it is real.
This article focuses on the initial installation of a new package. But the attack could be more insidious. Scenario: An attacker registers a fake package name, waits for developers to install it (e.g., in CI/CD), and then, after 2–3 weeks, pushes a malicious update.
That is a real pattern and the article does not cover it, since it is written around first contact. The good news is that this is where lockfiles finally earn their keep, because you do not get the malicious version until someone bumps it. The bad news is that the bump is usually a one line diff nobody reads, which is exactly how event-stream got through in 2018, so a release age minimum applied at update time matters just as much as at install time.
The attack event-stream involved handing over control of a popular package to an unknown person, which was the basis of the attack. A strengthened verification process for new maintainers—for example, by requiring two-factor authentication (2FA) for critical packages—would serve as a key barrier.
The 43% reproducibility number is what flips this from a cosmetic problem to a targeting API. If hallucinations were one-off noise, an attacker would need to register everything and most names would never get traffic. But when nearly half of fabrications are stable model behavior, the model is essentially running recon — telling you which fake names will recur across sessions, users, and time.
That changes the threat model. Typosquatting was a brute-force bet on human error rates. Slopsquatting is a targeted bet on model output distributions, and those distributions are learnable.
The huggingface-cli example is the cleanest proof: 15,000 downloads over three months on a name the model kept inventing. Not users making typos — a stable hallucination pattern with measurable demand. Lockfiles catch it after the fact, but the deeper fix is making the hallucination rate visible before install, not after.
Targeting API is a sharper name for it than anything I came up with. One small correction on lockfiles: they do not really catch it after the fact either, they just pin whatever version you pulled first, so a bad first install gets locked in rather than flagged. Agreed on surfacing it before install though, the hard part is that the signal lives in the assistant, not in the registry.
Good catch on the lockfile point — that's actually a stronger version of the argument. Lockfiles pin state, they don't evaluate it. A bad first install gets fossilized, not flagged. So the "check after install" layer I was implying was weaker than I thought. The only meaningful control point is pre-install.
And you've nailed the hard constraint: the signal about what's a hallucinated name lives in the model's generation distribution, not in the registry. The registry only knows what someone published. It can't tell you that 43% of sessions will generate the same fake package name because that's a model behavior, not a registry event.
So the only entity that can surface this pre-install is the assistant itself. Which means the control has to be inside the generation loop — the model (or the wrapper around it) needs to flag "I'm about to recommend installing something I've seen before but that I can't verify exists." A pre-flight check that says "this token looks like a package name, let me verify it against the actual registry before suggesting it." Not a post-hoc scan.
Agreed, and the wrapper is the practical place for it, since asking a model to know its own uncertainty is less reliable than just having it check the registry before suggesting anything. Boring, cheap, and it would catch most of this.
Yeah, and "boring and cheap" is honestly the highest compliment a control can earn. The wrapper checks the registry before the model suggests installing — one HTTP call, deterministic answer. No need for the model to reason about its own confidence, which as you said is unreliable at best.
The fact that this would "catch most of this" is the point. You do not need a perfect solution for a first-contact problem. You need a cheap pre-flight check that catches the 80% case. The remaining 20% (real packages with new malicious versions, genuinely novel attacks) is what the lockfile-and-scanner layers handle downstream.
Pre-install wrapper check → lockfile pin → post-install scan. Three boring layers, each doing what it is actually good at.
One thing I'd add to the mitigation section: a formal "maturity threshold" policy as an automated CI/CD gate.
You mentioned minimumReleaseAge (24h) and checking downloads/repo/README manually. But we can take it further:
Automatically block any new dependency that fails these criteria:
· Age < 6 months (not just 24h)
· Downloads < 1,000/week
· No public repo (GitHub/GitLab)
· No README or minimal documentation
Package managers already have this data. A pre-install hook could enforce it mechanically—no developer fatigue, no missed checks. It scales and gives clear rejection reasons.
One package slipping through because someone was in a hurry is all it takes. Automate the boring part.
Really like where you are going with this, I would just be careful about which signals do the heavy lifting. Downloads and a README are cheap for an attacker to fake, and a 6 month bar would block a lot of perfectly good new libraries, so people start overriding the gate out of habit and then you are worse off than before. What holds up is age plus a one time human approval the first time a package is admitted, with downloads and repo presence feeding that review instead of blocking on their own.
I want to set the direction for many parameters that he will decide on himself. I don't want to lock this into a single 6-month template with a fixed value.
Wow, this one is much more helpful than the last one! Thanks for the article! we'll go through everything here step by step at lunchtime 😁
😁 Thanks, happy this one was more useful!
The grounding failure here is one that retrieval-augmented pipelines expose cleanly: if the model's context window contained a live index of the actual registry at generation time, the hallucinated name would have no referent to attach to. The deeper problem is that most coding assistants treat package suggestions as free recall rather than constrained retrieval, so the hallucination surface is exactly as wide as the model's parametric knowledge. Slopsquatting is what happens when you let a probabilistic system make claims about a closed, enumerable world — the package registry — without checking membership. The fix is architectural: treat package name generation as a lookup, not a completion.
Lookup instead of completion is the right direction, but membership alone does not close it. By the time you run install, the slopsquatted package does exist on the registry, because the attacker registered it, so an existence check happily returns true. You need age, provenance and maintainer history on top, otherwise the retrieval step just confirms the trap.
Fascinating (and terrifying) analysis of slopsquatting! Beyond pre-commit hooks and package registry verification, are there any IDE plugins or agent guardrails you recommend that intercept non-existent package installations in real time?
Honestly I would not point you at an IDE plugin for this yet, since nothing I have used treats package existence checking as its main job at suggestion time. The controls I trust today sit lower down: ignore-scripts on by default, a release age delay like pnpm minimumReleaseAge, and a private registry proxy with an allowlist so an unapproved name fails before install rather than after. Less elegant than an editor warning, but it does not depend on anyone reading the warning.
Thanks for sharing this insight. It's interesting to me that as more automation becomes available to make development more convenient, it seemingly demands even more human attention, ironically. AI can accelerate workflows, but we still need to verify, validate, and think critically. Great read.
Thanks! That is the part that keeps surprising people: automation does not remove the attention, it just moves it somewhere less obvious. The work shifts from writing the code to deciding what you are willing to trust, and the second one is easier to skip.
Interesting take on how AI hallucinations can be weaponized in supply chains—typosquatting was bad enough, but this shows how much more subtle the threat can become. As someone working on secure GPU infrastructure, I've seen how hard it is to ensure model outputs are both accurate and safe, especially when they're used in automated systems.
Thanks for reading! The automated systems part is where it gets worst, since an agent resolving dependencies on its own removes the one step in the chain where a human might have paused on an unfamiliar name. That is why I would put the control at admission rather than at output quality, because you are never going to make the suggestions reliably correct.
The registry side is where this gets uncomfortable. Typosquatting defenses can compare a package to a known target. Slopsquatting often has no canonical target, just a plausible name the model keeps inventing. I would treat fresh packages first seen through generated code as quarantine candidates until provenance is clear, not merely run a string-similarity check.
That framing is sharper than mine and I think you are right that quarantine by provenance beats similarity here, precisely because there is no canonical target to measure against. The hard part is that the registry never learns a name arrived through generated code so that signal has to come from the client side,the assistant or the IDE, and get carried down. Which makes the interesting question who is trusted to attach it
The 43% rerun-stability figure is the one worth sitting with, because it generalizes one layer up. Agent skills now install by name too (npx skills add --skill ), and models recommend skills by name, so the same kill chain works with far fewer eyes on the payload than a pip package gets. We run a skills directory, and in the daily index duplicate or near-duplicate names are common across the ecosystem, so "a repo with this name exists" is zero evidence that it is the thing the model meant.
A sharper version of your "usually days old" check: compare the registration date against the assistant's training cutoff. A package that appeared on the registry after the model's cutoff but matches its suggestion exactly is close to a smoking gun, and it is a check a pre-install hook can run mechanically, no LLM involved.
The training cutoff comparison is a genuinely good heuristic, and I like that it needs no model at all to run. Worth noting cutoffs are fuzzy and models get retrained, so I would treat it as a strong signal rather than proof, but a name that appeared on the registry after the cutoff and matches the suggestion exactly is very hard to explain innocently. And you are right that skills installed by name inherit the same chain with even fewer eyes on them.
The concept of slopsquatting as a supply chain attack that leverages AI hallucinations is a fascinating and timely topic, and the author's explanation of how it exploits the weaknesses of AI assistants is particularly well-done.
If you're interested in sharing your expertise with a broader audience, consider cross-posting your content to ZyVOP, where you can connect with like-minded professionals and grow your readership.
Thanks for reading, glad the topic resonated.
One implementation detail I would add is making dependency admission a two-phase operation: the agent may propose a package, but a separate resolver must return registry metadata, provenance, release age, lifecycle-script status, and the exact version before policy can approve it. Keep the first install in a network-restricted sandbox with credentials stripped, then promote the resulting lockfile only after review. That covers the gap where a name exists but is still a brand-new, untrusted package. Have you considered recording that admission decision alongside the lockfile so a later agent cannot silently re-open it?
I had not thought about persisting the admission decision, and I think you are right that it is the missing half. Without it every agent run re-litigates the same question and eventually one of them says yes. The tricky part is keying the record on package plus version plus provenance rather than name, otherwise a later version quietly inherits an approval it never earned.
Slopsquatting is a fascinating attack vector because it exploits the trust model of package managers rather than any technical vulnerability. I've been experimenting with AI-generated code in production workflows and the hallucinated package problem is very real — even top-tier models will confidently suggest packages that don't exist. One mitigation I've found effective: maintain a local package allowlist in CI/CD that blocks any dependency not in your lockfile or approved registry. It's a blunt instrument but it completely eliminates this attack surface. The deeper question is whether package registries should implement some form of reputation scoring or verification — npm's provenance signatures are a step in the right direction.
The allowlist being blunt is exactly why it works, since it does not depend on anyone noticing anything. On provenance though, it proves who built the package, not that the package is the one you meant, and an attacker can publish with provenance just fine.
Really interesting read. I think one practical mitigation is to verify that a package actually exists and is trusted before installing it if it came from AI generated code. Using lockfiles together with an approved dependency list or an internal package registry also makes this kind of attack much harder.
Thanks! Worth splitting those two though, because in that pair the allowlist is doing all the work. A lockfile cannot help on the first install of a name you have never seen, it just pins whatever you pulled, so it holds the line afterwards rather than catching anything.
As a general rule of thumb, it's madness to allow the LLM to generate freeform code, because of problems like these.
I would put the line somewhere else. Freeform code is the part you actually read, so a bad function tends to get caught in review. The dependency name is the part nobody reads, and it runs before anyone gets a chance to look at it. Generating code is fine, admitting a new package on trust is the risky move.
You can't "review" something that's creating 50,000 functions per second. How many humans are you going to hire?
Nobody is merging 50,000 functions per second though, and if they are, that is a choice about merge rate rather than something the model imposed on them. But I agree review does not scale, which is exactly why I would not build the defense on it. An allowlist and install scripts off cost one decision per new dependency, not one per function, and they hold at any volume.
Allow lists on exposed functions is cool, but that doesn't allow for the agent to dynamically create tools. I'm probably not making much sense to you, but try it out here ti understand what I mean ... (Scroll below the fold ...)
That is a different problem though and a fair one. Dynamic tool creation is about what an agent is allowed to build at runtime while this article is about what gets admitted into your dependency tree. Both are admission questions just at different layers. I will take a look, thanks for the pointer.
The “looks plausible” step is the dangerous one because a successful import or passing test only proves the package executed, not that it is the intended package. I’d make the install boundary a CI policy: resolve the name in the registry, require an approved owner/source and minimum release age, pin the exact version plus lockfile hash, and inspect install scripts before execution. For AI-suggested dependencies, a failed registry lookup should be a hard stop rather than an invitation to search by a similar name. Have you tested how often that policy catches a hallucinated package without blocking legitimate new releases?
Honestly, no, I have not measured that and I would not want to quote a number I do not have. What I would say is that the error costs are very lopsided here: a blocked legitimate release costs one approval, a missed hallucination costs whatever credentials your build agent is holding. Your hard stop point is the one I would push hardest on because a failed lookup is exactly where an agent will helpfully retry with a similar name and land somewhere worse. And the line about a passing test only proving the package executed is the sharpest way I have seen anyone put it.
Slopsquatting is one of those security threats that feels obvious in hindsight but is incredibly dangerous in practice. As developers increasingly rely on AI-generated code, trust is shifting from official documentation to AI assistants.
The requests-oauth2-helper example is uncomfortably convincing — that's exactly the kind of name I'd install without a second thought. Makes me realize my usual defense of pinning versions does nothing here. Definitely adding a quick 'does this package actually exist' check to my habits.
Glad it landed and one tweak worth making before it becomes a habit: by the time you run install, the slopsquatted package does exist, because the attacker registered it. So the existence check on its own will happily say yes. Look at how old it is and whether there is a repo with real commit history behind it, since that is the part an attacker cannot fake in a week.
The reproducibility finding is the part that actually changes the threat model for me a one-off hallucination is annoying but not exploitable at scale. But 43% of fake names coming back on every single re-run means the model itself is doing target selection for the attacker, over and over, for free. That's a much scarier economics than "attacker guesses at typos and hopes."
The point about typosquat detection missing this entirely also lands hard, since nearly half these names aren't edit-distance-close to anything real. They're not corruptions, they're fresh inventions that just sound plausible in context, which means the defense industry built for one threat model (human typos) is structurally blind to a different one (machine confabulation) that happens to look similar on the surface.
The ecosystem comparison is the most actionable part though. Realizing Composer's "only root package scripts run" default is accidentally a security boundary, while npm's postinstall-by-default was a loaded gun until v12, makes me want to actually go check which install-time behavior my own stack defaults to instead of assuming they're all equivalent.
Go do that check, it is worth the ten minutes. Just watch out, because CI is probably not running the same npm you have locally. Build images tend to sit on an older version, so you can have a safe default on your machine while the pipeline is still happily running postinstall on every dependency. Easiest way to find out is to print the package manager version in your build log once and see what you actually get.
This is one of the most thorough breakdowns of this attack class I've read. The part about hallucinations being reproducible (43% recurring consistently) really changes the mental model — it's not noise, it's a reliable targeting signal for attackers.
The gap you described between existing defenses and this threat is what stood out most. Lockfiles protect continuity, scanners match known-bad, typosquat detection measures edit distance — and slopsquatting is none of those. It's a genuinely new name from a source people trust.
The HF intrusion incident a couple days ago (an AI agent autonomously compromising the platform) felt like the next evolution of this same theme. When AI is both the suggestion layer and the attack surface, the old trust boundaries just don't apply anymore. Thanks for writing this up with real evidence.
Thanks and that incident is a good pointer. The detail that got me is that the agent escaped its sandbox through a zero-day in a package registry cache proxy, so the exit route was package infrastructure, which is uncomfortably close to the Go module mirror story in the piece. Registry caching keeps showing up as the soft spot precisely because it is the boring plumbing everyone assumes is inert.
Hallucinations are indeed a serious problem
I made it by researching and testing it
I tried embedding a process that minimizes hallucinations as much as possible into a library
Sounds interesting, do you have a link? I would be curious what your library actually checks, since most of the mitigations I have seen work at install time rather than at generation time.
I uploaded it to GitHub, but..If you're interested, please leave a comment I’ll provide the link
Sure, drop the link here whenever, I would like to take a look.
Great read! I had not thought about AI hallucinations becoming a supply chain risk in this way. This is a great reminder that even when AI speeds things up, we still need to verify dependencies before trusting them. Thanks for sharing such a clear explanation!
Thanks, glad it was clear! That verification habit is really the whole defense, since everything else in the chain is just a normal install command doing its job.
The line that stuck with me: "the model is doing the target selection for them." Attackers don't need to guess typos anymore, they just watch what Copilot/ChatGPT keeps hallucinating and register the sticky ones.
Didn't realize hallucinated packages repeat 43% of the time on the same prompt. That turns this from random noise into a predictable attack surface, which is genuinely unsettling.
Also good to know Composer ignores a dependency's own install scripts by default, unlike npm. Makes ignore-scripts true feel like it should just be the default everywhere.
Simple takeaway: treat an AI's package suggestion like a random Stack Overflow answer, not a source. A quick npm view before installing costs nothing.
Small thing worth sharpening, the 43 percent is not how often a name repeats, it is the share of hallucinated packages that came back in all ten reruns, and 58 percent showed up in more than one. Which makes it worse rather than better. And on ignore-scripts, the ecosystem agrees with you now, since npm v12 turns automatic script execution off by default, so the sane setting is finally becoming the shipped one.
Agreed, that is the right place for it!
Slopsquatting is a real risk, not a punchline. AI hallucinations weaponize trust; verify prompts and harden defenses, non-negotiable.
100%
Though I would put the check at install rather than at the prompt, since the same prompt tends to hand you the same fake name again.
Nice work! 💪
Do you think package registries or package managers could eventually detect and block slopsquatting automatically, or will this always depend on developers verifying AI generated dependencies?
Partly but I do not think a registry can ever fully close it. What registries can fix is structural. like install scripts off by default, a cooling off period before a fresh version is installable, better provenance on who published what.... What they cannot answer is whether this particular name is the package a human actually meant, because a fabricated name is still a perfectly valid name. That last check has to happen where the suggestion is made, so I expect the assistants and package managers to carry more of it over time, with developers still holding the final call.
Thanks for sharing.
Regards
Important security points. We implemented similar auth flows for tools.shopveigo.com — our AI tools handle user photos and documents so security was top priority. CSP headers and input sanitization were critical for us.
Thanks for reading! Those are a different layer though, since CSP and input sanitization guard what happens at runtime in the browser, while slopsquatting fires at install time before your app ever runs. Worth checking your install script settings separately if AI is suggesting dependencies in that project.
That distinction between runtime and install-time execution is crucial, especially since install scripts run with full privileges before any browser sandboxing can protect us. It really highlights why we need to treat our lockfiles and dependency manifests with the exact same scrutiny as our core source code. Have you found any reliable CI pipeline integrations that successfully catch hallucinated packages before they make it into the build?
Nothing that detects hallucinated packages as a category, and I would be suspicious of anything claiming to. What does work in CI is mechanical: gate on the lockfile diff so any brand new dependency name in a PR needs explicit human approval, and pair it with a release age minimum so a package registered last week cannot be installed at all. Neither one knows about AI, they just make a new name expensive to add, which is enough.
Relying on mechanical CI gates like lockfile diffs and release age minimums is a much more pragmatic approach than trying to build a fragile AI detector. The age gate is especially clever since it completely neutralizes the time-to-exploit window for freshly generated slopsquatting targets. Have you found that enforcing strict lockfile approvals creates too much friction for developers prototyping quickly, or does the security benefit easily outweigh the slowdown?
The friction is real but it lands in the right place since the gate only applies to what enters the shared repo, not to what you do on your own machine. Prototype freely, install whatever you want locally and the approval only kicks in when a new name shows up in a PR. In practice adding a brand new top level dependency is not a daily event, so most developers hit the gate a few times a month rather than a few times a day and that is a trade I would take every time.
The timing window is what makes this so nasty — the model invents a plausible name, and by the time someone actually runs the install, an attacker may have already claimed it. We started treating AI-suggested package names like untrusted input: verify against the registry and check the publish date before anything reaches CI.
Slopsquatting is a fascinating and terrifying evolution of supply chain attacks because it shifts the vulnerability from human error to model confidence. I have been experimenting with adding a pre-install hook in our CI pipeline that cross-references any newly requested package against a known registry allowlist before the AI agent can execute the install command. It adds friction, but it seems like the only viable mitigation until package registries implement stricter cryptographic provenance by default. Have you seen any effective ways to sandbox autonomous AI coding agents so they cannot execute arbitrary shell commands without human approval?
Good security practices outlined. I'd emphasize that defense in depth matters — combining input validation with proper output encoding and CSP headers creates multiple layers that catch what any single approach might miss.
The 43 percent reproducibility stat is the one that changes the threat model entirely. If hallucinations were random noise, the attacker economics would not work — too many one-off names, not enough future exposure to justify registration costs. But nearly half are stable model behavior, which means the model is running reconnaissance for free.
The part about Levenshtein distance is the subtle one. If most hallucinated names were close to real ones, typosquat detection would catch them. But half are highly dissimilar — fully fabricated yet contextually believable. That means the defense has to be upstream of the install, not at the package name level. You need the assistant to validate its own output against a live registry before suggesting it, or the developer to verify before running.
This connects to the verification loop pattern from another thread on this site: generate, verify (deterministic, outside the model), approve, act. The verify step for package installation is a registry lookup — cheap, deterministic, and completely outside the model's reasoning context. Skipping it is what makes the kill chain work.
"The reproducibility is the reconnaissance" is going to live in my head rent free. Genuinely unsettling how much of this flips the economics in the attacker's favor.