OWASP Top 10 for AI-Generated Code: A01-A10 Risks and 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 codebases that mix secure and insecure patterns, and they optimize for code that works. The result runs fine in development and ships with well-known vulnerabilities.
A Stanford study (Perry et al., “Do Users Write More Insecure Code with AI Assistants?”) found that participants with an AI assistant wrote less secure code than those without one. AI writes the same insecure patterns humans have written for decades, only faster. OWASP gives you a framework to find and fix them.
Use this page as a priority map. Check A01 and A05 first. A03 appears whenever SQL or HTML is string-built, and A02 shows up as keys in the bundle. Mapping findings to OWASP also helps with auditors who already think in these categories.
The control strategy is unchanged: authorization, secrets hygiene, safe defaults, and verification on the live URL, repeated after every generative session.
A01: Broken Access Control in AI Code
Broken access control is the number one OWASP risk. AI tools generate routes, API endpoints, and database queries without authorization checks. Specific patterns:
- 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, orbalancebecause the handler saves the whole body. - Entity permissions left at
authorpublicon Base44-style platforms whenownerwas 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 check that the user is logged in and stop. Ask for the ownership check explicitly in the prompt.
A02: Cryptographic Failures
AI tools generate code with basic cryptographic weaknesses that automated scanners flag:
- 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 randomness:
Math.random()for session tokens or reset codes. - JWT
alg: noneor 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")}`;
}
Reject completions that simplify password storage to a single SHA-256 hex string.
A03: Injection
Injection patterns in AI-generated code:
- SQL injection: string concatenation in queries.
- NoSQL injection: Mongo operators from user JSON.
- XSS:
dangerouslySetInnerHTML, unescaped templates, LLM HTML rendered raw (LLM-rendered HTML). - Command injection:
exec/os.systemwith 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: quick examples often concatenate strings. Treat any `...${user}...` in a query or shell command as a review blocker.
A04: Insecure Design
AI optimizes for the demo path. Insecure design is an architecture that cannot be made safe without rework:
- 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_idfilters 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:
- What is the trust boundary? (browser vs server vs third party)
- Who can read/write each object?
- What happens if the client lies about price/role/id?
- Where do secrets live?
If you cannot answer, hold off generating the feature.
A05: Security Misconfiguration
Common misconfigurations in 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=developmentleft 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" }
]
}]
}
The code can look fine in git while production is open, so scan the running app.
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
latesttags 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 confirm it.
A07: Identification & Authentication Failures
Common flaws in AI-generated authentication:
- Weak session management: no expiry; tokens in
localStorage. - Missing MFA unless prompted.
- Insecure password reset: eternal tokens; user enumeration.
- No brute force protection on
/loginand/auth/v1/token. - Disabled email verification and no leaked password protection.
- OAuth redirect URI wildcards or leftover tunnel URLs.
- JWT verification that trusts
algfrom 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!,
);
A09: Security Logging & Monitoring Failures
AI-generated apps rarely include useful security telemetry:
- No audit logs for authz failures or admin actions.
console.logof 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)
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.254or 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
- Run automated SAST: Semgrep OWASP rulesets, secret scanners (gitleaks).
- Check every route: auth + authorization; no exceptions.
- Search for secrets: git history + deployed bundle.
- Test database access: anon key against every table (Supabase/Firebase rules).
- Verify input validation: malformed bodies on every write.
- Review auth flows: reset, session expiry, role escalation.
- Probe live deploy: Vibe Code Scanner for runtime gaps SAST misses.
- Confirm logging: failed login and 403s visible somewhere you watch.
- Review webhooks and SSRF features: signed webhooks; allowlisted fetches.
- Re-run after every agent feature: one-time audits go stale.
Automated scanning does not cover logic or access control. Those 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 |
Add this table to 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 go on a scheduled backlog with owners.
Tooling mapped to categories
| Control | Covers |
|---|---|
| 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. Combine several and re-run them after generative sessions.
Related Resources
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
Symptoms in a hypothetical 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.
Prompt rules that reduce Top 10 findings
Paste into agent system rules. Models still skip rules, so verify with dual-user tests, secret scanners, and live URL probes:
- 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.
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) touch more files than a human, which adds more of:
- New routes without ownership checks (A01)
- Temporary open CORS / debug flags left on (A05)
- New dependencies without audit (A06)
No new OWASP category is involved. Gate agent PRs with the same Top 10 map plus agentic code review for diff-scale issues (unrelated file “improvements,” CI disablement).
Relation to the OWASP Top 10 for LLM applications
This page covers the web Top 10. The OWASP Top 10 for LLM applications (prompt injection, training data poisoning, model DoS) is separate. When your product has 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
Use the web Top 10 for the HTTP app and LLM-specific guidance for the model layer.
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
Does the official OWASP Top 10 cover AI-generated code?
What is the most common OWASP risk in vibe-coded apps?
Can SAST cover the whole Top 10 for AI apps?
How should teams use this list?
Is prompt injection part of OWASP Top 10?
Where do Lovable and Supabase fit?
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