OWASP TOP 10 FOR AI-GENERATED CODE: SECURITY RISKS & FIXES (2026)

OWASP risks mapped to how AI coding tools actually fail: broken access control, injection, crypto failures, and security misconfiguration in generated apps.

Why OWASP Matters for AI-Generated Code

The OWASP Top 10 is the standard classification of web application security risks. AI code generators are trained on vast codebases that include both secure and insecure patterns. When generating code, they optimize for functionality – not security. The result is code that works perfectly in development but ships with well-known vulnerabilities.

Research from Stanford and NYU found that developers using AI assistants produce significantly less secure code than those writing manually. The problem is not that AI writes uniquely bad code – it writes the same insecure patterns that human developers have written for decades, but faster and at greater scale. OWASP provides the framework to systematically identify and fix these issues.

Use this page as a priority map, not a trivia list. In AI-generated apps, A01 and A05 dominate real incidents; A03 still appears whenever SQL or HTML is string-built; A02 shows up as keys in the bundle. Agents and multi-file tools increase volume; they do not invent a parallel taxonomy. Mapping findings to OWASP also helps you talk to auditors and security reviewers who already think in these categories.

If you only remember one thing: AI multiplies classic web risk density. Your control strategy is still authz, secrets hygiene, safe defaults, and verification on the live URL — just applied more often, after every generative session.

A01: Broken Access Control in AI Code

Broken access control is the number one OWASP risk, and it is the most common vulnerability in AI-generated applications. AI tools generate routes, API endpoints, and database queries without proper authorization checks. Specific patterns include:

  • Missing auth middleware – Express routes or Next.js API handlers with no session verification. Anyone with the URL can access protected data.
  • No RLS policies – Supabase tables created without Row Level Security. The anon_key grants full read/write access to all rows.
  • Open admin panels – Admin routes protected only by frontend conditional rendering, not server-side role checks. Navigating directly to /admin bypasses the “protection.”
  • IDOR / BOLA vulnerabilities – API endpoints that accept a user ID parameter without verifying the authenticated user owns that resource.
  • Mass assignment – clients set isAdmin, role, or balance because the handler saves the whole body.
  • Entity permissions left at auth or public on Base44-style platforms when owner was required.

Fix: every endpoint verifies identity and authorization before returning data. In Supabase apps, RLS on every table. In API apps, auth middleware plus ownership checks. Test with two users. See BOLA in AI-generated CRUD and mass assignment.

// Minimal ownership gate
const row = await db.item.findUnique({ where: { id } });
if (!row || row.ownerId !== session.userId) return res.status(403).end();
-- Supabase: enable RLS and scope rows
alter table public.projects enable row level security;
create policy "owner_all" on public.projects
  for all using (auth.uid() = owner_id)
  with check (auth.uid() = owner_id);

AI-specific note: models often implement “is the user logged in?” and stop. Ownership is a second sentence in the task prompt — add it deliberately.

A02: Cryptographic Failures

AI tools routinely generate code with cryptographic weaknesses. These are not exotic attacks – they are basic failures that automated scanners catch immediately:

  • Hardcoded secrets – API keys, database URLs, and JWT secrets embedded directly in source files or frontend bundles.
  • Weak hashing – MD5 or SHA-256 for passwords instead of bcrypt, scrypt, or Argon2.
  • No HTTPS enforcement – missing HSTS / redirects; mixed content calling APIs over HTTP.
  • Insecure randomnessMath.random() for session tokens or reset codes.
  • JWT alg: none or weak secrets – custom auth from a prompt (JWT patterns).
  • Homegrown encryption — rolling AES wrappers instead of platform KMS / libsodium defaults.

Fix: env vars and secret managers; bcrypt/Argon2; HTTPS at the edge; crypto.getRandomValues / crypto.randomUUID; prefer maintained auth libraries. Scan with Token Leak Checker.

import { randomBytes, scryptSync, timingSafeEqual } from "node:crypto";

function hashPassword(password: string) {
  const salt = randomBytes(16);
  const hash = scryptSync(password, salt, 64);
  return `${salt.toString("hex")}:${hash.toString("hex")}`;
}

Never accept completions that “simplify” password storage to a single SHA-256 hex string.

A03: Injection

Injection vulnerabilities remain common in AI-generated code despite decades of awareness:

  • SQL injection – string concatenation in queries.
  • NoSQL injection – Mongo operators from user JSON.
  • XSSdangerouslySetInnerHTML, unescaped templates, LLM HTML rendered raw (LLM-rendered HTML).
  • Command injectionexec / os.system with user paths.
  • Prompt injection into agent tools (browser, shell) when untrusted content is loaded (indirect prompt injection).
  • Template injection in server-rendered strings built from user fields.

Fix: parameterized queries; schema validation (Zod); framework escaping; never shell out on user input; sanitize or don’t render HTML from models.

-- bad: '... where id = ${id}'
-- good:
select * from users where id = $1;
// bad
exec(`convert ${userPath} out.png`);
// good: allowlist basename, spawn without shell

AI-specific note: concatenation is over-represented in training data “quick examples.” Your rules and review should treat any `...${user}...` in a query or shell as a review blocker.

A04: Insecure Design

AI optimizes for the demo path. Insecure design is choosing an architecture that cannot be safe without heroics:

  • Client-only “security” (hiding buttons, relying on obscurity).
  • Trusting the client for prices, roles, or discount codes.
  • Long-lived magic links without binding to device/session.
  • Multi-tenant apps with only user_id filters in the app layer and a shared DB role that can read all rows.
  • Using Memberships / static gates for truly sensitive documents (Webflow soft-gate problem).
  • “Security later” TODOs left in production because the agent marked the feature done.

Fix: threat-model the feature before prompting; put enforcement in the server/policy layer; assume every client input is hostile. Write non-goals into agent tasks: “Do not implement security only in the React layer.”

A short design gate before large prompts:

  1. What is the trust boundary? (browser vs server vs third party)
  2. Who can read/write each object?
  3. What happens if the client lies about price/role/id?
  4. Where do secrets live?

If you cannot answer, do not generate the feature yet.

A05: Security Misconfiguration

The dominant ops failure for AI deploys:

  • Default Firebase test-mode rules; Supabase RLS off.
  • CORS *; open storage buckets; debug routes in prod.
  • Verbose errors and public source maps.
  • Preview environments with production secrets (Vercel, Netlify).
  • Missing security headers (Security Headers Checker).
  • Public DB proxies (Railway, Neon).
  • NODE_ENV=development left on hosted templates.
  • Open Graph / reverse-proxy rewrites that become open redirects.

Fix: infrastructure-as-code for rules; deny-by-default; separate env scopes; checklist per host; automated config probes on the live URL.

// Example: explicit security headers (Vercel / similar)
{
  "headers": [{
    "source": "/(.*)",
    "headers": [
      { "key": "X-Content-Type-Options", "value": "nosniff" },
      { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" }
    ]
  }]
}

Misconfiguration is where “the code looks fine in git” and production is still open — runtime scanning is mandatory.

A06: Vulnerable and Outdated Components

AI pastes dependency versions from training data and invents package names:

  • Old Express/Next with known CVEs.
  • Hallucinated packages pre-registered by attackers (Package Hallucination Scanner).
  • Copy-pasted GitHub Gists as “utils.”
  • Transitive deps pulled by “just add this helper package.”
  • Unpinned latest tags in Dockerfiles generated by agents.

Fix: npm audit / Dependabot / Snyk; pin versions; verify new packages on the registry; prefer standard libraries over novel helpers from chat.

npm audit --audit-level=high
npm view some-package time  # does it even exist / when published?

Treat every agent-suggested dependency as untrusted until the registry and lockfile say otherwise.

A07: Identification & Authentication Failures

AI-generated authentication systems frequently have implementation flaws:

  • Weak session management – no expiry; tokens in localStorage.
  • Missing MFA unless prompted.
  • Insecure password reset – eternal tokens; user enumeration.
  • No brute force protection on /login and /auth/v1/token.
  • Disabled email verification and no leaked password protection.
  • OAuth redirect URI wildcards or leftover tunnel URLs.
  • JWT verification that trusts alg from the token header.

Fix: use Supabase Auth, Auth.js, Clerk, etc.; httpOnly cookies; rate limits; email confirm; HIBP checks; MFA for admin. Prefer not to invent auth from a single chat thread.

// Cookie-oriented sessions beat localStorage for XSS resilience
// (still fix XSS — cookies are not magic)
res.setHeader(
  "Set-Cookie",
  `session=${token}; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=604800`,
);

Test full flows: sign-up → verify → login → logout → reset → login again. See auth flows.

A08: Software and Data Integrity Failures

  • Unverified webhooks marking orders paid (Stripe webhook pattern).
  • Auto-updating agent skills / MCP servers without review.
  • CI that deploys from PRs without review (poisoned pipelines — poisoned CI pattern).
  • Unsigned software updates or fetch-and-eval of remote code.
  • Trusting client-reported “paid” flags without server verification.
  • MCP / tool plugins that execute with the developer’s full credentials.

Fix: verify signatures; lock MCP/skill sources; required reviews on main; no curl | sh in prod paths.

// Stripe: never trust raw body without constructEvent
const event = stripe.webhooks.constructEvent(
  rawBody,
  signature,
  process.env.STRIPE_WEBHOOK_SECRET!,
);

Integrity failures often look like “business logic bugs” until the first fraudulent order.

A09: Security Logging & Monitoring Failures

AI almost never adds useful security telemetry:

  • No audit logs for authz failures or admin actions.
  • console.log of full requests including tokens.
  • Stack traces to clients; silence on the server.
  • No alerts on stuffing, 500 spikes, or anomalous exports.
  • Preview and prod logs mixed without retention policy.

Fix: structured logs for auth events; redaction; centralize (Axiom, Datadog, Sentry); alert on thresholds; retain enough for incident response.

Log at least:

  • Failed logins (with rate and IP)
  • Authorization denials on sensitive objects
  • Admin mutations
  • Webhook verification failures
  • Secret access errors (without logging the secret)

If you cannot detect a credential-stuffing burst, you do not operate the app — you host it.

A10: Server-Side Request Forgery (SSRF)

Common when AI adds “fetch this URL” features, link previews, or webhook testers:

  • User-supplied URL fetched by the server → hits metadata 169.254.169.254 or internal 6PN hosts.
  • Open proxy redirects on Netlify/Vercel rewrites.
  • PDF/image converters that retrieve attacker URLs.
  • “Import from URL” CMS features on marketing sites.

Fix: allowlist schemes/hosts; block link-local and private ranges; no user-controlled hosts in reverse proxies; network egress policies.

import { URL } from "node:url";

function assertSafeUrl(raw: string) {
  const u = new URL(raw);
  if (u.protocol !== "https:") throw new Error("https only");
  // block localhost, RFC1918, link-local — use a maintained library in production
  if (u.hostname === "localhost" || u.hostname.endsWith(".internal")) {
    throw new Error("blocked host");
  }
  return u;
}

See SSRF / open redirect / OAuth.

How to Audit AI Code Against OWASP

A practical approach to auditing AI-generated code for OWASP compliance:

  1. Run automated SAST – Semgrep OWASP rulesets, secret scanners (gitleaks).
  2. Check every route – auth + authorization; no exceptions.
  3. Search for secrets – git history + deployed bundle.
  4. Test database access – anon key against every table (Supabase/Firebase rules).
  5. Verify input validation – malformed bodies on every write.
  6. Review auth flows – reset, session expiry, role escalation.
  7. Probe live deployVibe Code Scanner for runtime gaps SAST misses.
  8. Confirm logging – failed login and 403s visible somewhere you watch.
  9. Review webhooks and SSRF features – signed webhooks; allowlisted fetches.
  10. Re-run after every agent feature – AI velocity makes one-time audits stale within a week.

Automated scanning catches roughly half of issues. Logic and access control need human or agentic dynamic tests.

Per-PR OWASP tick map

If the PR touches… Check categories
New CRUD / tables A01, A03, A04
Auth / sessions A07, A02, A01
Payments / webhooks A08, A01, A04
File upload / URL fetch A03, A10, A05
Dependencies A06
Hosting / env / CORS A05, A02
Admin / roles A01, A04, A09

Print this table in your PR template for agent-authored work.

Priority matrix for vibe-coded apps

Priority Categories Typical AI failure
P0 A01, A02, A05 Open DB / leaked keys / open preview
P1 A03, A07 SQLi/XSS, weak auth
P2 A04, A08, A10 Bad design, webhooks, SSRF
P3 A06, A09 Deps and logging debt

Ship blockers: any P0 finding on a production URL with real users. P1 before public launch if you handle accounts. P2/P3 on a scheduled backlog with owners — do not pretend logging debt will self-heal.

Tooling mapped to categories

Control Helps most with
ESLint security / Semgrep A03, parts of A02/A07
Secret scanners + Token Leak Checker A02
npm audit / Snyk / Dependabot A06
Two-account manual or agent DAST A01
Host checklists (Vercel/Railway/…) A05
Webhook signature tests A08
Centralized logging product A09
URL allowlist libraries + egress policy A10

No single tool covers the Top 10. Compose a thin pipeline and re-run it after generative sessions.

AI Code Vulnerability Taxonomy

Complete classification of vulnerabilities in AI code

Secure AI Coding Practices

Prompts and practices for secure code generation

AI Code Review Guide

Framework for reviewing AI-generated code

SAST Tools for AI Code

Static tooling that complements this map

Vibe Coding Security Risks

Catalogue of failure modes across tools

Agentic Code Review Guide

How to review large agent diffs against these risks

Example mapping: one Lovable app → full Top 10

Imagine a generated SaaS with Supabase, Stripe, and an AI summary button:

Symptom on the live app Category
Anon reads invoices A01
sk_live in JS A02
Markdown render XSS in notes A03
Client-sent price trusted A04
CORS * + cookies A05
Hallucinated npm package A06
Unlimited login attempts A07
Stripe webhook no signature A08
No auth failure logs A09
“Fetch URL for summary” SSRF A10

Use this table in design reviews before the feature ships, not after the incident channel lights up.

Secure-by-default prompts that still need verification

Even with rules files that say “always use parameterized SQL,” models skip under pressure. Verification is the control that does not depend on model obedience: dual-user tests, secret scanners, live URL probes.

Team scorecard (monthly)

Track counts of: open RLS tables found in prod, secrets rotated after scans, agent PRs blocked for auth issues, time-to-fix critical findings. Publish the scorecard internally so velocity metrics are not the only dashboard.

Prompt library snippets that reduce Top 10 density

Paste into agent system rules (still verify):

- Never put secrets in NEXT_PUBLIC_, VITE_, or client bundles.
- Every data route checks auth and ownership (user B cannot read user A).
- Parameterized SQL only; no string-built queries or shell with user input.
- RLS enabled on every new table with owner policies; no USING (true).
- Webhooks verify signatures; clients cannot set paid/role/admin fields.
- Do not disable security tests or CI checks to make the build green.

Rules reduce frequency; dual-user tests and live scans catch obedience failures.

Mapping scanner findings to tickets

Scanner class OWASP Ticket title pattern
Anon table dump A01 “Enable RLS + owner policy on {table}”
sk_live in JS A02 “Rotate Stripe key; move to server env”
innerHTML user HTML A03 “Sanitize markdown sink in {file}”
CORS * + cookies A05 “Allowlist origins on API”
Hallucinated npm pkg A06 “Remove {pkg}; verify registry”
Unlimited login A07 “Rate limit /auth”
Webhook no sig A08 “constructEvent + raw body”
No auth logs A09 “Ship failed-login metrics”
Fetch user URL A10 “Allowlist hosts for preview fetch”

Agentic coding multiplies A01 and A05

Autonomous agents (Devin, Cursor Agent, Claude Code with tools) open more files per hour than a human. Empirically that increases density of:

  • New routes without ownership checks (A01)
  • Temporary open CORS / debug flags left on (A05)
  • New dependencies without audit (A06)

It does not create a new OWASP category. Gate agent PRs with the same Top 10 map plus agentic code review for diff-scale issues (unrelated file “improvements,” CI disablement).

What this page is not

This is not the OWASP Top 10 for LLM applications (prompt injection, training data poisoning, model DoS). Those are real and orthogonal. When your product is an LLM feature, map:

  • Prompt injection → A03/A08-ish integrity failures depending on tool use
  • Insecure plugin/tool design → A04
  • Excessive agency → A01 when tools can read all tenants

Keep web Top 10 for the HTTP app; add LLM-specific guidance for the model plane. Mixed apps need both.

Scan Your AI Code for OWASP Vulnerabilities

VibeEval automatically checks AI-generated apps against OWASP Top 10 categories on the live URL — broken access control, injection surfaces, crypto/key leaks, and misconfiguration — with findings you can paste back into Cursor, Claude Code, or Lovable.

COMMON QUESTIONS

01
Does the official OWASP Top 10 cover AI-generated code?
The OWASP Top 10 classifies web risks regardless of how the code was written. AI tools do not invent a new Top 10 — they reproduce the same classes faster and more uniformly. This page maps each category to patterns we see in Cursor, Copilot, Lovable, Bolt, and similar tools.
Q&A
02
What is the most common OWASP risk in vibe-coded apps?
A01 Broken Access Control — especially missing RLS, IDOR/BOLA on CRUD, and admin UI without server checks.
Q&A
03
Can SAST cover the whole Top 10 for AI apps?
No. SAST helps on injection, secrets, and some crypto issues. Access control, misconfiguration, and logging gaps need runtime tests and operational controls.
Q&A
04
How should teams use this list?
As a PR and launch checklist: for each new AI-generated feature, mark which OWASP categories it touches and what control you added. Pair with a live scan before production.
Q&A
05
Is prompt injection part of OWASP Top 10?
Classic Top 10 is web-app focused. Prompt injection shows up as injection/integrity/misconfig depending on architecture. See also agentic and LLM-specific OWASP guidance for model-layer risks.
Q&A
06
Where do Lovable and Supabase fit?
Missing RLS is A01. Leaked service_role keys are A02/A05. Open Storage is A01/A05. Map your stack to categories so fixes are prioritized by impact.
Q&A

MAP OWASP TO YOUR LIVE APP

Reading the Top 10 is research. We probe your deployed app for the same classes — with evidence you can fix today.

14-day free trial · No credit card · Cancel anytime

SCAN AGAINST OWASP