VibeSecurity

Fundamentals

AI Generated Code Vulnerabilities Mapped to the OWASP Top 10

AI generated code vulnerabilities are not a new species. They are the old OWASP Top 10 categories, reproduced quickly and at scale by tools that optimize for working features. This guide walks the 2021 list, describes how each category tends to appear in code an AI wrote, and then works through three of them in depth with corrected code.

By the VibeSecurity team5 min read

Which OWASP list are we using?

OWASP publishes the Top 10 as an awareness document for developers. This guide uses the 2021 edition, whose category names and numbers are listed on the OWASP Top 10 site. OWASP now also hosts a newer edition on the same site, so check which version a scanner or checklist refers to before comparing results.

The list is about categories of risk, not individual bugs. Treat it as a checklist for the questions to ask of any app, whoever or whatever wrote it.

The full mapping

The right-hand column is my analysis of how each category typically shows up when a model writes the code. It is a judgment, not a measured frequency.

OWASP Top 10:2021 and how it appears in AI-generated code
CategoryHow it shows up in AI-generated code
A01:2021 Broken Access ControlRoutes check login but not ownership; database tables left open; admin actions guarded only in the interface
A02:2021 Cryptographic FailuresSensitive data in plain text, homemade encryption, weak hashing for passwords, keys hard-coded
A03:2021 InjectionQueries built by joining strings with user input instead of parameters
A04:2021 Insecure DesignNo rate limit on login or OTP, trust in client-side prices, no thought given to abuse of a feature
A05:2021 Security MisconfigurationPermissive CORS, public buckets, debug mode on, default credentials, verbose errors
A06:2021 Vulnerable and Outdated ComponentsUnreviewed or stale packages installed to solve a problem
A07:2021 Identification and Authentication FailuresWeak session handling, predictable reset links, no lockout, tokens kept in insecure places
A08:2021 Software and Data Integrity FailuresUnsigned webhooks accepted as genuine, scripts loaded from untrusted sources, unchecked updates
A09:2021 Security Logging and Monitoring FailuresNo record of who did what, so an exposure goes unnoticed
A10:2021 Server-Side Request Forgery (SSRF)A feature that fetches a URL supplied by the user, such as link previews or image imports, with no destination limits

Deep example 1: Broken Access Control (A01)

Broken Access Control is first on the 2021 list, and it is the failure that generated code commits most naturally. The model writes a route that fetches an order by ID. The user is logged in, so the request passes. Nothing checks whose order it is.

The vulnerable pattern loads a record using only the ID from the request. The fix scopes the query to the authenticated user, and returns the same not-found response whether the record is missing or belongs to someone else, so the response does not confirm which IDs exist.

Vulnerable: any signed-in user can read any order
app.get("/api/orders/:id", requireUser, async (req, res) => {
  const order = await db.orders.findById(req.params.id);
  if (!order) return res.status(404).end();
  res.json(order);
});

The corrected access-control route

The corrected version identifies the user from the verified session on the server, never from a field the client sends, and includes that identity in the query itself. OWASP's authorization guidance describes the underlying principle: validate permission on every request and deny by default.

Fixed: the query is scoped to the authenticated user
app.get("/api/orders/:id", requireUser, async (req, res) => {
  const order = await db.orders.findOne({
    id: req.params.id,
    userId: req.user.id,
  });
  if (!order) return res.status(404).end();
  res.json(order);
});

Deep example 2: Injection (A03)

Injection happens when user input becomes part of a command the system executes. Models write it when asked for a quick search endpoint, because joining strings is the shortest code. OWASP's cheat sheet states that SQL injection is best prevented with parameterized queries, which keep the query structure separate from the data.

Vulnerable: input is joined into the SQL text
app.get("/api/products", async (req, res) => {
  const term = req.query.q;
  const rows = await pool.query(
    "SELECT id, name FROM products WHERE name ILIKE '%" + term + "%'"
  );
  res.json(rows.rows);
});

The corrected injection example

Pass the value as a parameter. The database driver sends the query and the value separately, so the input can never change the query's structure. Add basic validation on top, but treat the parameter as the actual defense.

Fixed: parameterized query
app.get("/api/products", async (req, res) => {
  const term = String(req.query.q ?? "").slice(0, 100);
  const rows = await pool.query(
    "SELECT id, name FROM products WHERE name ILIKE $1",
    ["%" + term + "%"]
  );
  res.json(rows.rows);
});

Deep example 3: Server-Side Request Forgery (A10)

SSRF appears when your server fetches a URL a user supplies. Typical features are link previews, avatar imports from a URL or webhook testers. If the destination is unrestricted, a user can make your server request addresses only the server can reach, such as internal services or cloud metadata endpoints.

OWASP's prevention guidance recommends an allowlist as the primary defense: match the host against approved destinations and build the request yourself, rather than accepting a complete URL from the user. Deny-lists are described as bypass-prone.

Vulnerable: fetches whatever URL it is given
app.post("/api/import-avatar", requireUser, async (req, res) => {
  const response = await fetch(req.body.url);
  const data = await response.arrayBuffer();
  await saveAvatar(req.user.id, Buffer.from(data));
  res.status(204).end();
});

The corrected SSRF example

The fix accepts only HTTPS URLs whose host is on a short list you control, and refuses redirects so an approved host cannot bounce the request elsewhere. If you truly need arbitrary destinations, that is a design decision to review with a security professional, not something to solve with a quick filter.

Fixed: allowlisted host, no redirects
const ALLOWED_HOSTS = new Set(["avatars.example-cdn.com"]);

app.post("/api/import-avatar", requireUser, async (req, res) => {
  let target;
  try {
    target = new URL(req.body.url);
  } catch {
    return res.status(400).json({ error: "Invalid URL" });
  }
  if (target.protocol !== "https:" || !ALLOWED_HOSTS.has(target.hostname)) {
    return res.status(400).json({ error: "Host not allowed" });
  }
  const response = await fetch(target, { redirect: "error" });
  if (!response.ok) return res.status(502).end();
  const data = await response.arrayBuffer();
  await saveAvatar(req.user.id, Buffer.from(data));
  res.status(204).end();
});

Using the list without being overwhelmed

For a small team, the practical move is to rank the categories by your exposure. If your browser talks to a database, start with A01 and A05. If you take payments, add A04 and A08. If your app fetches URLs or accepts uploads, add A10. Then review the rest as capacity allows.

Whichever categories you pick, test them against your own app and re-check after every generated feature. A checklist only helps if someone runs it.

Frequently asked questions

Does AI-generated code have more vulnerabilities than human code?

I am not aware of a settled, reliable answer, and I will not quote a number. What is clear is that AI tools reproduce the same categories OWASP already lists and rarely flag them, so unreviewed generated code needs the same checks as any code.

What is the number one OWASP risk for web apps?

In the 2021 edition, A01 Broken Access Control is first. It covers users acting outside their permissions, such as reading other people's records. It is especially common in AI-built apps because a working preview never reveals missing ownership checks.

Is there a newer OWASP Top 10 than 2021?

OWASP's site now also presents a newer edition alongside the 2021 list. The 2021 categories are still widely referenced in tools and audits, so confirm which version a document or scanner uses before comparing results.

Can I fix these issues just by asking the AI to fix them?

Sometimes, but verify. Ask for a specific fix, such as scoping queries to the signed-in user, then test with two accounts. A model can claim a fix and leave a gap, so the test matters more than the reassurance.

Put it into practice

Sources

  1. 1.OWASP Top 10:2021
  2. 2.OWASP Authorization Cheat Sheet
  3. 3.OWASP Query Parameterization Cheat Sheet
  4. 4.OWASP SSRF Prevention Cheat Sheet
  5. 5.Supabase docs: Row Level Security