security·6 min read

Why 45% of AI-Generated Code Fails Security Audits — And What the Failure Modes Are

The Veracode 2025 AI Code Security Report found that 45% of AI-generated code fails basic security audits. Here are the specific failure patterns.

Richard — ZipLoom

July 19, 2026

The Veracode 2025 AI Code Security Report found that 45% of AI-generated code fails basic security audits. This is not a surprise to anyone who has read the commit history of an AI-generated application. But 'AI code has security problems' is not actionable. Knowing the specific failure modes is. This post covers the patterns, with code examples where relevant.

Source

The 45% figure comes from Veracode's 2025 AI Code Security Report, which analyzed code produced by GitHub Copilot, ChatGPT, and Claude across multiple codebases. The methodology and full report are available at veracode.com.

Failure mode 1: Missing authentication checks

AI-generated API routes frequently implement authentication for the 'happy path' (the main protected endpoint) and forget to add it to helper endpoints, admin routes, or callback URLs. The pattern looks like this:

typescript
// AI-generated Next.js API route — correctly protected
export async function GET(req: Request) {
  const session = await getSession(req);
  if (!session) return new Response("Unauthorized", { status: 401 });
  // ... return user data
}

// AI-generated admin route — often NOT protected
export async function GET(req: Request) {
  // No session check — the AI generated the "admin" route
  // separately from the main routes and forgot to add auth
  const allUsers = await db.select().from(users);
  return Response.json(allUsers);
}

Fix: audit every API route for an authentication check, not just the ones you intentionally built as protected. Search your codebase for `export async function GET` and `export async function POST` and verify each one.

Failure mode 2: SQL injection via template literals

AI coding tools sometimes generate raw SQL queries using template literals when they should use parameterized queries. This is more common when the AI is asked to build a search feature or a complex filter.

typescript
// Vulnerable: AI-generated search endpoint
const query = `SELECT * FROM posts WHERE title LIKE '%${searchTerm}%'`;
const results = await db.execute(query);
// An attacker can set searchTerm to: ' OR 1=1 --
// This returns every post in the database

// Correct: parameterized query
const results = await db
  .select()
  .from(posts)
  .where(like(posts.title, `%${searchTerm}%`));
// The ORM handles escaping — searchTerm is never interpolated into SQL

Failure mode 3: Exposed error messages

AI-generated error handlers frequently return the full error message to the client, including database error messages, stack traces, and internal implementation details. A Postgres error message like `relation 'users' does not exist` tells an attacker your table name. A stack trace tells them your file structure.

typescript
// Vulnerable: AI-generated catch block
} catch (error) {
  return Response.json({ error: error.message }, { status: 500 });
  // Returns: { "error": "relation "admin_users" does not exist at character 14" }
  // Now the attacker knows your table name

// Correct: generic error message to client, real error logged server-side
} catch (error) {
  console.error("[API Error]", error); // logged — visible to you, not the user
  return Response.json({ error: "Something went wrong" }, { status: 500 });
}

Failure mode 4: Missing rate limiting

Authentication endpoints — login, password reset, email verification — are almost never rate-limited in AI-generated code. An attacker can attempt unlimited password guesses against any account without throttling.

This is harder to miss in code review because rate limiting is often external to the application (an API gateway, a middleware layer, a service like Upstash). AI tools don't generate this infrastructure because it's not in the code files they're writing.

Failure mode 5: Insecure direct object references

An IDOR vulnerability lets a user access another user's resources by changing an ID in a URL. AI-generated CRUD endpoints frequently look like this:

typescript
// Vulnerable: AI-generated GET /api/posts/[id]
export async function GET(req: Request, { params }: { params: { id: string } }) {
  const session = await getSession(req);
  if (!session) return new Response("Unauthorized", { status: 401 });

  // Bug: fetches the post by ID without checking it belongs to the current user
  const post = await db.select().from(posts).where(eq(posts.id, params.id));
  return Response.json(post);
}
// A logged-in user can access any other user's private posts
// by iterating through IDs: /api/posts/1, /api/posts/2, etc.

// Correct: filter by both ID and user
const post = await db.select().from(posts)
  .where(and(eq(posts.id, params.id), eq(posts.userId, session.user.id)));

Why AI tools generate these patterns

AI coding tools are trained on code from the public internet. The public internet contains a lot of tutorial code, demo applications, and early-stage projects that prioritize making things work over making things secure. The models learn to produce code that passes immediate functional tests — not code that resists adversarial inputs.

This is not a criticism of the tools. They do exactly what they are optimized to do: produce code that matches the statistical patterns of the code they were trained on. Security is a property of systems under adversarial conditions. That is hard to capture in a training signal.

The practical implication

None of the failure modes above are exotic. They are the same vulnerability classes that have existed in web applications for decades. AI tools did not invent them. They reproduce them at higher volume than human developers do, because they produce more code faster without the natural pause points (code review, pull requests, security scans) that catch these issues in professional software development.

The remediation is also not exotic: code review, automated security scanning, and a pre-deployment checklist. The same practices that have always caught these issues in human-written code catch them in AI-generated code. The tooling just needs to run automatically, because the pace of AI-assisted development makes manual review impractical at scale.

ZipLoom

Security scan on every deploy. Flat price. No meter.

ZipLoom checks RLS, secrets, CVEs, and license compliance before your app goes live — automatically, on every deploy. First Thread founding price: $99/yr, locked for life.

Share this article

https://ziploom.dev/blog/why-ai-code-fails-security-audits

AI code securitysecurity auditCursor securityClaude code securityAI coding tool vulnerabilities

Related articles