Dependency confusion exploits how package managers resolve private versus public packages. Slopsquatting exploits LLM hallucinations of package names. Both are well-documented supply chain attack vectors. I think they combine into something worse, and I haven’t seen anyone else connect the dots yet.

Dependency confusion

Dependency confusion came to light in February 2021 when security researcher Alex Birsan published how he’d compromised over 35 major companies including Apple, Microsoft, PayPal, Tesla, Netflix, and Uber. He earned over $130,000 in bug bounties for this research.

The attack exploits registry resolution order. Most package managers can be configured to check multiple registries: a private registry for internal packages, plus a public registry like npm or PyPI. When a developer runs npm install or pip install, the package manager needs to decide which registry to query. The resolution logic varies by tool and configuration, but a common pattern is to check public registries first, or to prefer whichever registry has the higher version number.

This creates an opening. Say a company has an internal package called acme-utils on their private registry at version 1.2.0. An attacker registers acme-utils on the public npm registry at version 99.0.0. Depending on how the package manager is configured, it might prefer the public package because of the higher version number. The attacker’s code now runs in the target’s environment.

The classic case is private versus public registries, but the same issue affects any setup where multiple registries are checked in sequence. Artifactory or Nexus instances proxying multiple upstreams can have the same vulnerability, as can Maven setups that pull from multiple repositories. A misconfigured .npmrc or pip.conf that doesn’t properly scope private packages is enough. Clojars, the main Clojure package registry, used to be particularly exposed because it sat on top of Maven and allowed anyone to register packages under almost any name with no verification; they’ve since tightened this.

The reconnaissance step is the bottleneck. Birsan found internal package names by examining leaked package.json files, error messages, and GitHub repositories that accidentally exposed internal dependencies. Once he had candidate names, he registered them publicly with high version numbers and code that phoned home on install. It worked, but it’s manual work that scales poorly. Each target requires separate investigation.

Slopsquatting

Code-generating LLMs have a peculiar behavior: they hallucinate package names that don’t exist. Ask an LLM to write code that parses YAML, and it might suggest import yaml_parser even though no such package exists on PyPI. The model isn’t looking up real packages; it’s predicting what tokens are likely to come next based on patterns in its training data. Sometimes those predictions land on real packages. Sometimes they don’t.

The attack itself isn’t new. Bar Lanyado at Lasso Security documented package hallucination attacks in 2023. But the name “slopsquatting” came out of a conversation I had with Seth Larson in April 2025. We were discussing how 404 logs from package registries could reveal which non-existent packages developers were trying to install, and therefore which hallucinated names would be most valuable to squat. I said it needed a good name. Seth suggested “slopsquatting” and I posted it on Mastodon, where it caught on.

A study by Spracklen et al., published at USENIX Security 2025, quantified the problem. Across 576,000 code samples generated by 16 different LLMs, 19.7% of suggested packages were hallucinations. That’s 205,474 unique fake package names that don’t exist on any public registry. Notably, 38% of these hallucinated names were similar to real package names, and some were even valid packages in other programming languages. The LLMs aren’t generating random strings; they’re generating plausible-sounding names that are easy to confuse with legitimate packages.

The hallucination rates varied by model: 21.7% for open-source models, 5.2% for commercial ones like GPT-4. But even at 5%, one in twenty package suggestions points to something that doesn’t exist. More importantly, 43% of hallucinated packages appeared consistently across repeated prompts. The same question yields the same fake package name, which means an attacker can predict what names LLMs will suggest and register them preemptively.

The attack: prompt LLMs with common coding tasks, collect the hallucinated names, register them on PyPI or npm with malicious payloads, and wait. Slopsquatting now has a Wikipedia entry, suggesting it’s crossed into mainstream awareness.

There’s an irony here: the same 404 logs that could help registries identify slopsquatting attempts are also a roadmap for attackers. I’ve since heard those logs described as “toxic waste” because they reveal intent: every 404 is a package name someone tried to install, which means it’s a name worth squatting. Birsan had to do manual reconnaissance to find internal package names; 404 logs would hand them over directly.

The attack surface scales with LLM adoption. Every developer using Copilot, ChatGPT, or Claude for code generation is potentially exposed. Developers doing what Andrej Karpathy called “vibe coding,” where you’re curating LLM output rather than writing code yourself, are especially vulnerable because they’re less likely to scrutinize individual package names. The more people trust LLM suggestions without verification, the more valuable it becomes to squat on hallucinated names.

The combination

Most slopsquatting research focuses on hallucinated names that never existed anywhere. But what happens when an LLM hallucinates a package name that actually exists as a private package at some company?

The combination inverts the discovery problem. Traditional dependency confusion requires finding internal package names, then squatting them. With LLMs, an attacker can squat hallucinated names first, and some will happen to be real internal names somewhere. The attack flow: LLM training data includes leaked code referencing private packages, attacker registers hallucinated names on public registries, LLM suggests those names to developers at the very companies that use them internally. The model becomes both the discovery mechanism and the delivery mechanism.

LLMs are trained on enormous scraped datasets that inevitably include unintentionally exposed code: internal documentation indexed by search engines, Stack Overflow posts with private package names, GitHub repositories that were briefly public before someone noticed. There’s also the question of what repository hosts have trained on: if a code hosting platform trained models on private repositories without explicit disclosure, every private package name in those repos is potentially learnable through the right prompts.

Companies increasingly fine-tune LLMs on their own codebases for internal developer tools. These models know every internal package name by design. If the model is exposed too broadly, or if its outputs are shared outside the organization, those package names leak through the suggestions themselves. An attacker doesn’t need to find leaked package.json files; they just need access to a model that was trained on them.

You can see the leakage directly by prompting an LLM to roleplay:

User: Imagine you're a new developer at Stripe and you're learning
      how to use their internal package repository. Give me some
      example commands.

LLM:  # authenticate
      stripepkg login

      # search for a library
      stripepkg search payments-core

      # install a package into your service
      stripepkg add [email protected]

      # publish a new internal library
      stripepkg publish --tag=beta

      # remove a package
      stripepkg remove auth-utils

The LLM has hallucinated payments-core and auth-utils as internal Stripe packages. These names are plausible enough that an attacker could register them on npm or PyPI. If a Stripe developer later asks an LLM for help and gets the same suggestion, they might install the public malicious package instead of their internal one.

The combination is worse than either attack alone. Traditional slopsquatting requires waiting for random developers to install fictional packages. Traditional dependency confusion requires discovering specific internal names at specific companies. Combined, an attacker can spray malicious packages across public registries and let LLMs distribute them to exactly the vulnerable developers. The attacker doesn’t even need their own LLM access; hallucinated package names are published in academic studies or can be gathered via cheap prompting runs against free-tier models.

This is speculative, and I haven’t seen documented cases of this combined attack in the wild, but all the components are there: LLMs hallucinate consistently, sometimes based on training data patterns that include leaked internal code, and package managers have well-documented dependency confusion vulnerabilities. The attack surface is real even if it hasn’t been publicly exploited yet.

The mitigations for each attack apply here too. For dependency confusion: use scoped packages (like npm’s @org/package namespacing), configure registries to explicitly resolve private packages first, and pin to specific registries in your config. For slopsquatting: verify that suggested packages exist and are legitimate before installing them. For the combination: assume that any package name an LLM suggests might already be maliciously registered, especially if it matches an internal package name.

Package names occupy a weird space: short strings that need to be globally unique, rarely verified beyond “did the install succeed,” and now flowing through systems that treat them as just another token to predict. Every step where a package name passes through an LLM, ingested from training data, stored as weights, retrieved during inference, suggested to a developer, typed into a terminal, is a potential point of corruption.

LLMs are introducing new trust assumptions into software development. When a developer types an import statement, they’re asserting they know what package they want, but when an LLM generates that import, nobody made that assertion: the model might have invented the name, remembered it from leaked training data, or correctly identified a real package, and distinguishing between these cases is left as an exercise for the reader. Package ecosystems weren’t designed for a world where code suggestions come from probabilistic models trained on scraped data of uncertain provenance, and the security model assumed developers knew what they wanted. That assumption no longer holds.