KognitaKognita.

Blog

AI Suggests Dependencies That Don't Exist. That's a Security Problem.

9 min read

You asked the AI what package to use for rate limiting in your Node service. It gave you a name, a version, and a code snippet. You ran npm install. Everything installed. The code ran. Two weeks later, your security scanner flagged the package — the version the AI suggested has a known prototype pollution vulnerability that was patched in the next minor release. The AI's training data predated the CVE disclosure. It had no way to know.

That is the optimistic scenario. The pessimistic one is that the package name the AI suggested does not exist at all — and a malicious actor registers it on npm while it is sitting in your team's install history.

What the data says

Sonatype analyzed 36,780 dependency upgrade suggestions from AI coding tools and found that 27.8% pointed to versions or packages that were non-existent, deprecated, or carried known security issues. That is roughly one in four AI dependency suggestions that cannot be trusted as-is. The finding is not about a single tool — it reflects the structural limitation that all current AI coding tools share: a training data cutoff and no live connection to package registries.

The 27.8% figure understates the operational risk for a few reasons. It measures individual suggestions, not deployment impact. A single bad dependency suggestion that lands in a shared package or a core service affects every downstream consumer. And it measures only the suggestions that were identifiably wrong at the time of analysis — it does not capture suggestions that were valid when made but became problematic after a subsequent CVE disclosure.

The problem is not that AI tools are bad at dependencies in particular. It is that they are bad at anything that requires live, current knowledge of an external state — and package versions are exactly that kind of external state. The npm registry has over 2.5 million packages. New versions are published constantly. CVEs are disclosed continuously. A model with a training cutoff is working from a snapshot of that registry that is always at least several months out of date.

The three types of bad AI dependency suggestions with real examples
The three types of bad AI dependency suggestions

TYPE 1: NON-EXISTENT PACKAGE OR VERSION
  AI suggests: npm install @aws-sdk/client-s3@3.523.0
  Reality: version 3.523.0 does not exist on npm
  Risk: developer installs nearest available version without checking,
        or package name gets registered by a malicious actor

  AI suggests: pip install langchain-community==0.2.1
  Reality: version 0.2.1 was never published; the version sequence jumped
  Risk: pip install fails silently or resolves to an unexpected version

TYPE 2: DEPRECATED OR ABANDONED PACKAGE
  AI suggests: npm install request@2.88.2
  Reality: the request package was deprecated in 2020 and is unmaintained
  Risk: no security patches for new CVEs; some registries still serve it

  AI suggests: npm install node-uuid@1.4.8
  Reality: node-uuid was deprecated in favor of the uuid package in 2016
  Risk: installs technically functional but unsupported code

TYPE 3: PACKAGE WITH KNOWN CVEs
  AI suggests: npm install lodash@4.17.15
  Reality: lodash@4.17.15 has CVE-2021-23337 (command injection via template)
           and CVE-2020-8203 (prototype pollution)
  Risk: developer ships vulnerable dependency; AI training data predates the CVE

  AI suggests: pip install cryptography==2.9.2
  Reality: cryptography==2.9.2 has multiple resolved CVEs in newer versions
  Risk: developer ships known-vulnerable crypto implementation

Sonatype analysis (36,780 AI dependency suggestions): 27.8% were
non-existent, deprecated, or had known security issues.

Why AI hallucinates package versions

AI models do not query package registries. They generate text based on patterns in their training data. When an AI coding tool suggests aws-sdk@2.1456.0, it is not checking whether that version exists — it is generating a version number that looks plausible based on version numbers it has seen. The generated version may exist. It may not. The model has no mechanism to distinguish between the two at inference time.

Version hallucination happens because version numbers are mostly opaque to the model's training signal. The model sees many examples of package@major.minor.patch and learns the format. It does not learn a reliable mapping from package name to currently-available versions, because that mapping is constantly changing and was already partially stale when the training data was collected. The model learns to produce plausible-looking version strings, not correct ones.

Package name hallucination is different. Some hallucinated package names are genuinely invented — names that have never existed on any registry. Others are plausible recombinations of real package names: @stripe/node-client instead of stripe, or express-rate-limiter instead of express-rate-limit. These close-but-wrong names are more dangerous than completely invented ones, because they are more likely to fool a developer who does not check carefully, and they are more likely to be registered by a squatter because the name is discoverable through AI suggestions.

Package squatting: how non-existent suggestions become attack vectors

Package squatting — also called dependency confusion or typosquatting — is not new. Attackers have long registered package names that are typographical variants of popular packages (crossenv instead of cross-env) or that match internal package names that organizations might have on private registries. What AI-generated dependency suggestions add is a new, scalable mechanism for generating target package names.

When an AI coding tool hallucinates a package name, that name becomes signal. If the suggestion appears in blog posts, Stack Overflow answers, GitHub issues, or Slack threads — which it does, because developers share AI suggestions — the name propagates. Attackers who monitor these channels can register the suggested package names on npm, PyPI, or other registries before anyone notices the original suggestion was hallucinated.

Attack chain: AI hallucination to code execution via package squatting
Package squatting attack chain: from AI hallucination to code execution

STEP 1: AI generates a dependency suggestion
  Developer asks: "What package should I use for structured logging in Node?"
  AI responds: "Use @company/structured-logger — it provides typed log levels
               and integrates with OpenTelemetry"
  Reality: @company/structured-logger does not exist on npm

STEP 2: Package name becomes known
  -> Developer searches npm, finds the package missing
  -> Developer posts in Slack: "Does anyone know if @company/structured-logger
     is published? Claude suggested it"
  -> Or: developer assumes it exists, runs npm install, fails — now the name
     is in the team's public install history

STEP 3: Malicious actor registers the package
  -> Attacker monitors AI-suggested package names that do not exist
  -> Registers @company/structured-logger on npm
  -> Publishes a package that contains legitimate-looking logging code
     plus a postinstall script that exfiltrates environment variables

STEP 4: Developer installs the malicious package
  -> A different developer on the team asks the same AI question
  -> AI suggests the same package name
  -> Developer runs npm install @company/structured-logger
  -> npm finds the now-registered package and installs it
  -> postinstall script executes: environment variables, tokens, and
     secrets from the developer's machine are sent to attacker's server

STEP 5: Lateral movement
  -> CI/CD pipeline picks up the new dependency in a PR
  -> npm install runs in the pipeline environment
  -> Pipeline secrets (AWS credentials, deploy keys, API tokens) are exfiltrated
  -> Attacker has production access

Time from AI suggestion to compromise: hours to days.
Detection without dependency auditing: often zero.

The attack chain is particularly effective against engineering teams because it exploits the trust that developers place in AI suggestions. A developer who asks an AI for a dependency recommendation is already in a mode of accepting the AI's judgment. When the package installs without error, the trust is reinforced. The malicious package is indistinguishable from a legitimate one until the postinstall script runs — and by then, the damage is done.

This is a legitimate reason security teams hesitate to approve AI coding tools, and why the CISO's concerns about AI coding tooling often have more substance than developers acknowledge. The attack surface is not hypothetical. Security researchers have demonstrated the full squatting chain against AI-suggested package names in controlled environments, and real-world incidents attributed to AI-assisted squatting have been disclosed by multiple organizations.

The deprecated version problem

Non-existent packages are visible failures — the install fails and the developer knows something is wrong. Deprecated packages and packages with known CVEs are invisible failures. They install successfully. The code compiles. Tests pass. The vulnerability ships to production and sits there until a scanner finds it, or until it is exploited.

The deprecated package problem is structural. When a package is deprecated, the deprecation notice goes into npm's registry. It does not go into the AI model's training data retroactively. A model trained before a deprecation was announced will continue to suggest the deprecated package as if it were current. The model is not wrong from the perspective of its training data — the package was valid when the training data was collected. It is wrong from the perspective of current registry state, which the model cannot access.

CVE-affected versions have the same structural problem with additional severity. A CVE is disclosed after a vulnerability is discovered. The AI's training data predates the disclosure by at least the training cutoff gap — often six months to a year, sometimes longer. The model suggests a version that was secure at training time and is now known to be vulnerable. The suggestion is not a hallucination in the strict sense — the version exists, it is real, it once had no known vulnerabilities. It is an outdated fact presented as current information, which is arguably more dangerous than an outright hallucination because it passes the basic verification checks that catch invented versions.

What safe dependency management looks like with AI in the loop

The answer is not to stop using AI for dependency decisions. AI tools are genuinely useful for identifying candidate packages, explaining tradeoffs between libraries, and generating integration code. The answer is to treat AI dependency suggestions as research starting points, not installation targets.

A safe AI-assisted dependency workflow
Safe AI-assisted dependency management

BEFORE INSTALLING — verify every AI-suggested package:

  1. Check the registry directly
     npm info <package>@<version>     # verify version exists
     pip index versions <package>     # list available versions
     Look for: publication date, download count, recent activity

  2. Cross-reference against your existing lockfile
     Check package-lock.json or yarn.lock: is the package already
     a transitive dependency at a different version? Understand why.

  3. Verify the package is not deprecated
     npm info <package> deprecated    # deprecated field if set
     Check the GitHub repo: is it archived? Last commit?

  4. Run a vulnerability scan before committing
     npm audit                        # checks npm advisory database
     pip-audit                        # checks PyPI advisory database
     snyk test                        # broader CVE coverage
     trivy fs .                       # container-aware scanning

  5. Verify the package origin
     Look at the publisher account: when was it created?
     A package registered last week for a name that "should" be old is a red flag.

  6. Pin versions in lockfiles, never ranges in install commands
     Wrong:  npm install lodash          # resolves to latest
     Right:  npm install lodash@4.17.21  # pin the exact version you audited

AFTER INSTALLING — keep it clean:
  -> Run npm audit / pip-audit in CI on every PR
  -> Block merges if new critical/high CVEs are introduced
  -> Set up Dependabot or Renovate to surface version drift
  -> Do not trust AI to suggest upgrade targets — verify against changelogs

The workflow is not about not using AI for dependency decisions.
It is about not treating AI suggestions as verified facts.

The workflow adds friction that feels unnecessary when AI suggestions are right — which is most of the time. The friction is the point. The 27.8% of suggestions that are wrong are indistinguishable from the 72.2% that are right at the moment of suggestion. The verification step is what separates them. Skipping verification because most suggestions are fine is exactly the pattern that makes package squatting attacks effective.

At the team level, the right approach is governance, not individual developer vigilance. Individual vigilance is not a reliable security control — it depends on every developer consistently following the verification workflow, which does not happen at scale. Governance means running automated dependency auditing in CI, blocking merges on new high-severity CVEs, and having a documented process for evaluating new dependencies that applies regardless of how the dependency was suggested. Security engineers who govern AI coding tool access increasingly include dependency verification in the policy framework, treating AI-suggested dependencies as untrusted input that requires the same validation as any other external input.

The grounding problem

There is a version of this problem that a better-grounded AI can partially address, even without live registry access. An AI session that understands your codebase knows what dependencies you already use. It knows that your Node services use pino for logging, ioredis for Redis, and prisma for database access. When asked for a logging package, it can suggest the package already in your codebase rather than suggesting a new one that may or may not exist at the version it names.

This does not solve the registry-staleness problem — if the AI suggests upgrading pino to a version that does not exist, grounding in your codebase does not prevent that. What it does is reduce the blast radius of hallucination. An AI that knows your existing dependencies defaults to suggesting what you already have rather than inventing new packages. The dependency suggestion problem becomes smaller because the suggestion surface is narrower: "upgrade this existing dependency" rather than "add this new one."

A managed codebase context platform that maintains a current semantic index knows your full dependency graph: what you use, at what versions, and where. When your AI coding session has that context, it gives suggestions that start from your actual dependency state rather than from a generic model of what a Node service might use. The AI becomes harder to fool into suggesting non-existent packages because it already knows what packages you have.

Final take

AI models have a training cutoff. Package registries do not wait for training cutoffs. Every day that passes between a model's training data snapshot and the present is a day during which packages can be deprecated, versions can be withdrawn, and CVEs can be disclosed. The AI does not know about any of it.

The 27.8% figure is not a benchmark to optimize — it is a floor. It reflects the state of a registry that is always moving relative to a model that is always standing still. The gap does not close as models improve. It only closes if models get live registry access, which current architectures do not provide.

The developers who ship secure code with AI assistance are the ones who never treat a dependency suggestion as a verified fact. They check the registry. They run the audit. They treat AI suggestions about external systems the same way they would treat a suggestion from a colleague who has been on sabbatical for a year — useful direction, requires verification before acting on it.