Auditing the Dependencies an AI Chose for You

Written By
SprintX Team
AI & Product Engineering
August 01, 2026
7 min read

How to run a dependency audit on an AI-generated npm project — spotting hallucinated packages, unmaintained libraries, license risk, and the CVEs that actually matter.
You did not choose these packages. A model did, one prompt at a time, and each choice looked reasonable in isolation. Now your package.json has 60 direct dependencies, your lockfile pulls in 900 more, and nobody on the team can explain why there are three date libraries and two HTTP clients in the same app.
That is not a hypothetical. It is the single most common finding when we open an AI-built repo for the first time. The code usually runs. The dependency tree is where the liabilities hide — because dependencies are the one part of your app you did not write, cannot see, and ship to production anyway.
This is a practical pass you can run in an afternoon. No security background required, though a paranoid streak helps.
Why AI-picked dependencies fail differently
Human engineers accumulate dependencies slowly and with friction. Someone has to justify the addition in review, and there is social cost to adding a package for one function. An AI assistant has no such friction. It reaches for a library because that library appeared frequently in its training data, not because it fits your app, is maintained, or is licensed compatibly.
Three consequences follow, and they compound:
The model recommends packages by popularity-in-2023, not health-in-2026. Libraries that were the obvious pick two years ago may now be archived, replaced by a platform primitive, or maintained by one person who stopped answering issues.
It sometimes recommends packages that do not exist at all. The Cloud Security Alliance found roughly 19.7% of 2.23 million AI-generated code samples referenced hallucinated package names. Attackers noticed. They register the invented names and wait for someone to run an install — a technique now widely called slopsquatting. Your build succeeds, and you have just executed a stranger's postinstall script.
It duplicates capability. Ask for a form in one session and a table in another, and you get two different validation libraries and two state managers. Every duplicate is bundle weight, another upgrade path, and another CVE surface.
The five failure modes worth checking
| Failure mode | How you spot it | What it costs you |
|---|---|---|
| Hallucinated or typosquatted package | Package has no repo link, very low downloads, first published weeks ago | Arbitrary code execution at install time |
| Abandoned library | Last publish 2+ years ago, open issues unanswered, archived repo | No security patches, blocked runtime upgrades |
| Duplicate capability | Two libraries solving the same problem in one tree | Bundle size, inconsistent behavior, doubled upgrade work |
| License mismatch | AGPL or SSPL deep in the tree of a closed-source SaaS | Legal exposure surfaced during due diligence |
| Real, reachable CVE | Advisory in a package your code actually calls | Exploitable path into your app |
Note the last row carefully. Most vulnerability reports on an AI-built repo are noise — advisories in build-time tooling that never runs in production. The reachable ones are the short list that matters.
The audit, step by step
1. Get a lockfile, then freeze it
Plenty of AI-built repos have no lockfile at all, or one that drifted from package.json because someone edited the manifest by hand. Without a lockfile you are not shipping the code you tested — you are shipping whatever the registry served that morning.
Delete node_modules, install fresh, commit the lockfile, and switch CI to an install command that refuses to modify it ('npm ci', 'pnpm install --frozen-lockfile', or the yarn equivalent). If that command fails, your manifest and lockfile disagreed and you just learned something useful.
2. Verify every direct dependency is a real, healthy project
For each name in package.json, check three things: does it link to a real source repository, when was it last published, and does the download volume match a library anyone actually uses? A package with 40 weekly downloads and no GitHub link is either abandoned or bait. 'npm view <name>' shows publish dates, maintainers, and the repository field in one command.
Pay closest attention to packages with plausible-sounding, slightly-off names — the utility helper, the client SDK with an unfamiliar scope, the "official" integration that is not on the vendor's own docs page. That is exactly the gap slopsquatting exploits.
3. Triage the vulnerability report instead of obeying it
Run your package manager's audit command, then ignore the total. What matters is the subset that is (a) in runtime code, not dev tooling, and (b) reachable from a code path a user can trigger. A prototype-pollution advisory in a test fixture generator is not your problem this week. A prototype-pollution advisory in the request parser sitting in front of your API is.
Sort by that filter and you will typically go from 40 alerts to three or four that deserve a fix today. The rest go on the maintenance list. If your audit output is genuinely overwhelming, that itself is a signal — this is one of the standard findings in a full AI code audit.
4. Check maintenance, not just version numbers
An up-to-date version of an abandoned package is still an abandoned package. For each significant runtime dependency, look at the last release date and whether recent issues get responses. Anything untouched for two years in a fast-moving ecosystem is a future emergency — the kind that arrives on the day you need to upgrade Node or React and cannot.
5. Read the licenses once, properly
Most of your tree will be MIT or Apache-2.0 and irrelevant. What you are hunting is a copyleft license — AGPL, SSPL, or a custom "source available" grant — sitting somewhere in a closed-source product. Generate a license list with your package manager or a license-checker tool, scan for the handful of restrictive ones, and resolve them now. Finding an AGPL library during technical due diligence is a bad day; finding it on a quiet Thursday is a chore.
Deleting is the highest-value fix
The best outcome of a dependency audit is a smaller tree. Every package you remove is one you never have to patch, upgrade, or explain.
Look for three easy wins. Single-function packages you can replace with ten lines of your own code or a platform built-in. Duplicate capability, where you pick one library and migrate the two files using the other. And packages nothing imports at all, which is more common than you would think in AI-built repos, because the model added them for an approach it later abandoned.
Then pin what remains. Exact versions in the lockfile, a policy for how upgrades happen, and one place where an automated update bot files pull requests you review rather than auto-merge.
Keeping it clean without ceremony
An audit is a snapshot. What keeps a dependency tree healthy is a small, boring routine: automated update PRs reviewed weekly, an install command in CI that fails on lockfile drift, a rule that adding a direct dependency requires naming what it replaces, and a scheduled re-run of the full audit every quarter. That is roughly an hour a month, and it is the difference between routine upgrades and a rewrite eighteen months from now.
If dependencies were the only mess in the repo, this pass may be all you need. If the audit turned up secrets in the git history or authorization logic that never worked, treat it as the start of a broader effort to fix AI-generated code before you scale usage — and get the rest of the path to production in order along the way, which we lay out in taking a vibe-coded app to production.
Frequently asked questions
How do I know if a package an AI recommended actually exists? Look it up on the registry before installing. A real library has a linked source repository, a publish history going back further than a few weeks, and download volume consistent with its claimed popularity. If any of those are missing, do not install it — and be especially skeptical of names that are one character or one word away from a package you know is real.
Is a high npm audit count a real problem? Usually not on its own. Most reported advisories live in build and test tooling that never runs in production, and many are unreachable from your code. Filter to runtime dependencies on paths a user can trigger, fix those, and schedule the rest. A four-figure alert count with no triage tells you nothing.
How many dependencies is too many? There is no magic number, but every direct dependency should have an owner-level answer to "what does this do and what would we use instead?" If nobody can answer that for a third of your package.json, the tree is bigger than the team can carry, and trimming it will pay for itself the first time you need an urgent upgrade.
If an AI assistant assembled your dependency tree and nobody has reviewed it since, you are carrying risk you cannot see and did not choose. SprintX audits AI-built codebases end to end — supply chain, secrets, authorization, and the fixes that make them stick. Send us your repo and we will tell you what is in it.


