The Vulnerability Classes AI Code Generators Keep Producing

Written By
SprintX Team
AI & Product Engineering
July 30, 2026
7 min read

AI coding tools fail in patterns, not at random. These are the vulnerability classes they produce again and again — and the fastest way to find them in your own repo.
The interesting thing about reviewing AI-generated codebases for a living is how little variety there is in the findings. Different founders, different products, different builders — Lovable, Bolt, Cursor, Replit, v0 — and the same eight or nine problems, in roughly the same order of severity.
That is good news. Random bugs are expensive to hunt. Systematic ones you can go straight at with a checklist. Escape.tech scanned 5,600 vibe-coded applications and turned up more than 2,000 vulnerabilities; the distribution was not exotic. It was the boring stuff, repeated at scale.
Here is what keeps showing up, why the models produce it, and how to check whether your app has it.
Why the failures are so repetitive
A language model writes the code that most plausibly follows your prompt. Your prompt described a feature. It did not describe an attacker, a malicious payload, a second tenant, or a user who edits the request in their browser tools — so none of those appear in the output.
Three mechanics drive nearly every finding:
- No threat model in the context window. The model optimizes for "this works," and working code is the training signal. Nothing rewards refusing to trust input.
- Client-side thinking. Generators are strongest at UI. When they need to enforce a rule, they enforce it where they are already working: in the component. Hiding a button is not access control.
- Tutorial-shaped defaults. Quickstart code — public buckets, permissive CORS, service-role keys, wide-open policies — dominates the training data because it dominates the internet.
Understanding the mechanic matters, because it tells you where to look. Anything that should be enforced on a server, in a database, or at a trust boundary is where you will find the holes.
The classes that keep shipping
| Class | What it looks like in the repo | How it gets exploited |
|---|---|---|
| Broken object-level authorization | Query filters by an ID that arrives from the client | Change the ID in the URL, read someone else's record |
| Missing server-side authorization | Role checks live in React, not in the API | Call the endpoint directly with any token |
| Exposed secrets | Keys in client bundles, .env committed, service keys in the browser | Anyone reads the bundle and uses your key |
| Unvalidated input | No schema on the request body, no DB constraints | Malformed or oversized payloads, injected fields |
| Insecure direct storage access | Public buckets, signed URLs that never expire | Enumerate and download files |
| Dependency risk | Hallucinated or unmaintained packages | Supply chain compromise |
| No rate limiting | Every route open, AI routes uncapped | Credential stuffing, credit burn |
| Verbose errors | Stack traces and query text returned to the client | Free schema map for an attacker |
Authorization, in two flavors
This is the single biggest category, and it splits usefully in two. Authentication — is this person logged in — is usually present, because a login screen is a visible feature someone asked for. Authorization — is this specific person allowed to touch this specific row — is usually absent, because it is invisible.
The tell is a query that takes an identifier from the request and uses it without asking whether the caller owns it. In Supabase apps the same failure appears as tables with row-level security disabled or a policy of "true"; we walk that pattern in detail in Supabase RLS mistakes in AI-built apps. For the general shape of the bug and how to test for it in ten minutes, see why AI-generated apps keep shipping auth bypasses.
Secrets that were never meant to leave the server
GitGuardian counted 28.65 million new hardcoded secrets in public GitHub commits during 2025, up 34% year over year — and commits with AI assistance leaked at roughly 3.2% versus a 1.5% baseline. In practice we find three variants: a key prefixed for client exposure that should never have been client-side, a .env file committed in the first week, and an admin or service-role key used from a browser-reachable path because it was the fastest way to make a query work.
Input that nobody checked
Generated forms validate in the UI. The API accepts whatever arrives. Add a schema validator at every route boundary and constraints in the database — NOT NULL, unique, foreign keys, length limits. Half the "weird data" bugs founders report are just the absence of a unique index.
Dependencies you did not choose
The Cloud Security Alliance found roughly 19.7% of 2.23 million AI-generated code samples referenced package names that do not exist. Attackers register those names and wait. That is slopsquatting, and it is the one supply-chain risk unique to this era of development — covered properly in hallucinated packages and slopsquatting.
Finding them in your own repo
Do this in order. It takes an afternoon and finds most of what matters.
- Grep the client bundle for key-shaped strings. Build for production, then search the output for "sk_", "service_role", "AKIA", and any provider prefixes you use. Anything found is already public — rotate it.
- Scan git history, not just the working tree. Deleted secrets live forever in commits. See finding every secret an AI left in your repo.
- Call your own API with a second account. Log in as user B, take an ID belonging to user A, and request it directly. If it returns, you have a critical.
- List every table and its policies. Anything unprotected is unprotected in production too.
- Run the dependency audit. Check that every package in the manifest actually exists on the registry and has a real maintenance history.
- Hit an endpoint 200 times in a loop. If nothing stops you, add limits.
What to fix first
Rank by blast radius, not by effort. Exposed secrets and cross-tenant data reads are ship-blockers — they are unbounded, silent, and reportable. Missing rate limits and verbose errors are next, because they are cheap to fix and amplify everything else. Input validation and dependency cleanup are the long tail.
Resist the urge to rewrite. In almost every rescue we run, the product logic and interface are fine and the security work is additive: move enforcement to the server, close the database, rotate the keys, add the schema checks. That is days of work, not a new codebase. If you want the full mapping against a standard framework, the OWASP Top 10 read through AI-generated code lines each category up against what the generators actually produce.
Frequently asked questions
Are newer AI models producing more secure code? Somewhat, on the narrow prompts. They still cannot invent requirements you did not state. If nothing in your prompt or repo describes multi-tenant isolation, the model will not enforce it — no matter how good it gets at syntax.
Can I just ask the AI to fix the vulnerabilities it wrote? For mechanical issues, yes: adding a validation schema or moving a key to an environment variable is well within reach. For authorization it is unreliable, because the correct answer depends on your business rules, which the model is guessing at. Have a human define the rules and let the tool implement them.
Does a scanner catch all of this? Scanners are excellent at secrets and known-vulnerable dependencies, and nearly useless at broken authorization — it looks like ordinary working code. Run the scanners, then have someone test access boundaries by hand with real accounts. A proper audit does both, and the manual half is where the criticals come from.
If your app was built fast and you now need to know what is actually exposed, that is a finite question with a written answer. SprintX audits AI-generated codebases, ranks findings by real-world blast radius, and fixes the criticals without a rewrite — send us your repo or builder link.


