Quick Answer
Apps built with tools like Cursor, Bolt, Lovable, and Claude Code show the same patterns again and again: API routes with no authentication check, secrets exposed in frontend bundles, and little meaningful test coverage. The code compiles, the UI looks polished, but the security and structural foundations are consistently weak. This report breaks down ten common issues, what causes them, and how to close the gaps before production.
Why This Data Matters Now
The volume of AI-generated code shipping to production in 2026 is unprecedented. GitHub's Octoverse 2025 found that 80% of new developers on GitHub use Copilot in their first week. Tools like Bolt and Lovable scaffold full-stack applications in minutes. Cursor and Windsurf embed AI directly into professional IDE workflows. Claude Code generates entire feature branches from natural language descriptions. v0 produces deployment-ready React components on demand.
But speed creates a blind spot. When you can build a full SaaS product in a weekend, there is no natural pause point for security review. The code works, the demo looks great, and the deploy button is one click away. What gets missed in that flow is not random - it follows patterns. Specific categories of security, quality, and performance issues surface in AI-generated codebases with striking regularity, regardless of which tool generated them.
CodeRabbit's December 2025 analysis of 470 open-source pull requests found that security issues were up to 2.74x higher in AI-co-authored code than in human-only code. The question is not whether AI-generated code has problems - it does. The question is which problems appear most often, and how to systematically eliminate them. That is what this data answers.
10 Common Issues in AI-Generated Codebases
The following table lists ten issues that show up again and again in applications built with Cursor, Bolt, Lovable, Claude Code, v0, and Windsurf. These findings span security vulnerabilities, structural code quality, dependency health, and production readiness - the four dimensions that determine whether an app is actually safe to ship.
| # | Issue | Category | Severity |
|---|---|---|---|
| 1 | Missing SSL certificate monitoring | Monitoring | High |
| 2 | Missing security headers (HSTS, CSP) | Security | High |
| 3 | Missing React error boundaries | Quality | Medium |
| 4 | Unprotected API routes | Security | High |
| 5 | God files (500+ lines) | Structure | Medium |
| 6 | Hardcoded secrets in frontend code | Security | Critical |
| 7 | Hallucinated npm imports | Dependencies | High |
| 8 | Excessive dependency count | Dependencies | Medium |
| 9 | Low test coverage (ratio below 0.3) | Quality | Medium to High |
| 10 | Below-average Lighthouse performance | Performance | Medium |
Two things stand out. First, these issues are not obscure edge cases - they are fundamental gaps in authentication, monitoring, and structural hygiene. Second, the most critical findings (hardcoded secrets, unprotected routes) are exactly the ones attackers look for first.
VibeDoctor's own scan data shows how common two of these risks are. Of 963 codebases scanned between 31 July and 14 October 2026, 654 (67.9%) had at least one dependency with a known CVE and 364 (37.8%) contained at least one string that looked like a secret.
The Security Layer: What Vibe Check Scans Reveal
Security findings dominate the list, and the patterns are consistent. An unprotected API route is an endpoint that accepts requests from anyone on the internet without verifying identity. This is not a hypothetical risk - it is an open door.
The root cause is predictable. When a developer prompts "create an endpoint that returns user data," the AI generates exactly that: a route that returns user data. It does not add authentication middleware unless explicitly asked, because the prompt did not mention it. The same logic applies to exposed secrets. AI tools using Supabase or Stripe will place API keys directly in frontend environment variables (prefixed with NEXT_PUBLIC_ or VITE_) because that is the fastest way to make the code work.
// ❌ BAD: AI-generated API route - no auth, no validation, SQL built from user input
export async function GET(req: Request) {
const { searchParams } = new URL(req.url);
const userId = searchParams.get('userId');
// Direct database query with no ownership check
const userData = await db.query(
`SELECT * FROM users WHERE id = '${userId}'`
);
return Response.json(userData.rows[0]);
}
// ✅ GOOD: Authenticated, validated, parameterized
import { auth } from '@/lib/auth';
import { z } from 'zod';
const paramsSchema = z.object({
userId: z.string().uuid(),
});
export async function GET(req: Request) {
const session = await auth();
if (!session) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
const { searchParams } = new URL(req.url);
const parsed = paramsSchema.safeParse({
userId: searchParams.get('userId'),
});
if (!parsed.success) {
return Response.json({ error: 'Invalid input' }, { status: 400 });
}
// Only allow users to access their own data
if (parsed.data.userId !== session.user.id) {
return Response.json({ error: 'Forbidden' }, { status: 403 });
}
const userData = await db.query(
'SELECT id, name, email FROM users WHERE id = $1',
[parsed.data.userId]
);
return Response.json(userData.rows[0] ?? null);
}
Missing security headers are equally concerning. Headers like Strict-Transport-Security, Content-Security-Policy, and X-Frame-Options are deployment-level configurations that AI code generators almost never set. Vercel and Netlify send HSTS by default, but not the rest. The OWASP Top 10 (2025) lists security misconfiguration - which includes missing headers - as the second most critical web application security risk (A02).
The Structural Layer: What Vibe X-Ray Patterns Show
Beyond individual findings, the structural analysis of AI-generated codebases reveals deeper architectural problems. When you map the import graph, module boundaries, and symbol relationships across an entire project, a pattern emerges: AI-generated code is structurally fragile.
Many AI-built apps have at least one god file: a file over 500 lines that handles routing, data fetching, business logic, and rendering in a single module. These files are the blast radius amplifiers - a bug in one function can cascade through hundreds of lines of tightly coupled logic. Because so much of the app depends on a god file, a single change to it can break multiple features.
The dependency picture tells a similar story. AI tools add packages freely, and more dependencies mean more transitive attack surface. A typical JavaScript project pulls in hundreds of transitive dependencies, and any of them can carry a known vulnerability. Every extra package is one more place for a CVE to appear before a single line of application code is considered.
Perhaps the most uniquely AI-specific finding is hallucinated imports: AI-generated code that imports an npm package that does not exist. These phantom dependencies silently break builds or, worse, create supply chain attack vectors if someone registers the hallucinated package name on npm with malicious code. This is a problem that simply did not exist before AI code generation.
The Production Layer: What Vibe Monitoring Patterns Expose
Scanning does not stop at the source code. The production health of deployed AI-generated apps reveals a third category of problems that only surface when the application meets real traffic and real infrastructure.
Missing SSL monitoring is the easiest of these gaps to overlook. AI tools do not set up any alerting for certificate expiration. If a certificate expires because renewal quietly failed, the site goes down behind a browser-level security warning. No amount of clean code matters if users cannot reach the application.
Lighthouse performance scores tell another story. AI-generated sites often lose points from three sources: unoptimized images (AI tools do not configure next/image properly or compress assets), excessive JavaScript bundles (client-side dependencies all ship to the browser), and missing code splitting. These are not code bugs - they are deployment and build configuration gaps that accumulate across the bloated dependency trees AI tools create.
Without a React error boundary, a runtime JavaScript error (and there will be one) can crash the entire application to a white screen. No fallback UI, no error reporting, no recovery path. Next.js and Vercel provide error boundary patterns, but AI generators rarely include them unless the prompt specifically requests error handling.
What This Means for Founders and CTOs
The data does not argue against vibe coding. Building with AI is too productive to abandon, and the tools will only improve. But it does argue that the gap between "it works" and "it is production-ready" is wider for AI-generated code than most builders realize. The issues found are not theoretical - they are the exact attack vectors that automated scanners, penetration testers, and bad actors look for.
Automated scanning platforms like VibeDoctor's Vibe Check run 149+ checks across security, code quality, dependencies, and AI-specific patterns, providing a Vitals Score that benchmarks your app against production-ready standards. Free to sign up.
Three practices close the majority of these gaps:
- Scan every commit, not just pre-launch. AI-generated code drifts. Each prompt cycle introduces new routes, new dependencies, and new configuration. Continuous scanning catches regressions the moment they appear - not three months later when an attacker finds them.
- Track structural health over time. A single scan shows findings. Tracking your codebase structure across versions shows trends: is dependency count growing? Are god files multiplying? Is the import graph getting more tangled? Trend data turns reactive fixing into proactive architecture decisions.
- Monitor production, not just code. SSL expiry, uptime, Lighthouse scores, security headers - these are runtime properties that change independently of your source code. A certificate renewal failure or a CDN misconfiguration will take your site down regardless of how clean your codebase is.
Veracode's State of Software Security 2023 found insufficient input validation flaws in 41.6% of applications scanned with static analysis. The tools generate functional code at unprecedented speed, but functional is not the same as safe. Scanning makes that distinction measurable.
Related reading: is vibe coding bad?.
Which AI coding tool produces the most secure code?
No tool consistently produces secure code out of the box. All of them can miss authentication middleware, security headers, and rate limiting unless you ask for them. The safest approach is any tool combined with automated scanning before deployment.
Are these issues specific to vibe-coded apps or do hand-coded apps have them too?
Many of these issues also appear in hand-coded applications - missing security headers and low test coverage are industry-wide problems. The difference is frequency and concentration. CodeRabbit's analysis found security issues up to 2.74x more often in AI-co-authored pull requests, because the generation process optimizes for functionality, not defense. A human developer is more likely to add auth middleware from habit; an AI only adds it when prompted.
What is a hallucinated import and why is it dangerous?
A hallucinated import is when an AI model generates an import statement for an npm package that does not exist. The model invents a plausible-sounding package name based on training data patterns. This breaks builds at best. At worst, an attacker registers the hallucinated package name on npm with malicious code, and any developer who runs npm install unknowingly executes it. This is called slopsquatting, and hallucinated imports create the perfect conditions for it.
How many checks should a production-ready scan include?
A thorough scan covers at minimum: secret detection, CVE scanning for dependencies, static analysis for code quality, security header verification, SSL certificate validation, Lighthouse performance metrics, and AI-specific pattern checks like hallucinated imports and god files. Scanning only one dimension - for example, only dependencies - misses the majority of issues found in AI-generated codebases.
Can I fix all these issues by writing better prompts?
Better prompts help but do not solve the problem. You can prompt for authentication and input validation on specific routes, but you cannot prompt for the absence of all 149+ patterns simultaneously. Security is a system-level property, not a per-function property. Prompting handles individual gaps; scanning handles the system. Both are necessary.