SecurePilot
All posts
6 min read·

Broken Access Control in AI-Generated APIs: 5 Patterns to Fix

Broken Access Control is the OWASP #1 vulnerability and the most common flaw in AI-generated API code. Here are the 5 patterns AI assistants consistently miss, with real examples and fixes.

Broken Access Control has been the number one vulnerability in the OWASP Top 10 since 2021. It is also the most common class of vulnerability we find in AI-generated API code. The reason is straightforward: AI assistants are excellent at generating endpoints that read and write data, and consistently poor at adding the authorization checks that protect those endpoints.

This guide walks through the specific access control patterns AI coding assistants miss, with real code examples and fixes.


🛡️ SecurePilot found these exact patterns, and 165+ more

Missing auth middleware, IDOR, client-supplied user IDs, and mass assignment are the top findings in AI-generated REST APIs we scan. Broken Access Control is the OWASP #1 vulnerability because it's invisible in testing but devastating in production. SecurePilot flags all five patterns in this article automatically, in under a second.

Why AI Gets Access Control Wrong

When you prompt an AI to "create an endpoint that returns a user's orders," it focuses on the happy path: querying the database and returning the data. The question of "which user is allowed to see which orders" requires understanding your authentication system, your data model, and your business rules, none of which the AI knows unless you explicitly include them in the prompt.

Even when you include some context, the AI often adds a token verification check at the top of the function but forgets to verify that the authenticated user is actually authorized to access the specific resource they are requesting. These are two very different checks.

1. Missing Authentication Entirely

The most obvious form. AI generates an admin or sensitive endpoint with zero authentication middleware.

// Vulnerable - no auth on a destructive admin action
app.delete('/api/admin/users/:id', async (req, res) => {
  await db.user.delete({ where: { id: req.params.id } });
  res.json({ success: true });
});

Any HTTP client can hit this endpoint and delete any user. This is common in AI-generated code because the AI treats the /admin prefix as implicit security. It is not. Authentication must be enforced in code.

// Safe - auth + role check
app.delete('/api/admin/users/:id', requireAuth, requireRole('admin'), async (req, res) => {
  await db.user.delete({ where: { id: req.params.id } });
  res.json({ success: true });
});

2. Authenticated but Not Authorized (IDOR)

Insecure Direct Object Reference (IDOR) is the most common access control flaw in AI-generated REST APIs. The endpoint requires a valid token, but it does not check whether the token owner is allowed to access the requested resource.

// Vulnerable - authenticated but no ownership check
app.get('/api/orders/:orderId', requireAuth, async (req, res) => {
  // req.user is set by auth middleware, but we never verify ownership
  const order = await db.order.findUnique({
    where: { id: req.params.orderId },
  });
  res.json(order);
});

Any logged-in user can enumerate order IDs and retrieve other users' order details. They just need a valid account and knowledge that orderId is an integer (or UUID) that can be iterated.

// Safe - ownership enforced in the query
app.get('/api/orders/:orderId', requireAuth, async (req, res) => {
  const order = await db.order.findUnique({
    where: {
      id: req.params.orderId,
      userId: req.user.id, // only returns if this user owns it
    },
  });
  if (!order) return res.status(404).json({ error: 'Not found' });
  res.json(order);
});

3. Trusting Client-Supplied User IDs

A subtle but extremely common AI-generated pattern: the user ID is taken from the request body or query params rather than from the authenticated session.

// Vulnerable - userId from request body (attacker-controlled)
app.put('/api/profile', requireAuth, async (req, res) => {
  const { userId, name, bio } = req.body;
  await db.user.update({
    where: { id: userId }, // attacker can set this to anyone's ID
    data: { name, bio },
  });
  res.json({ success: true });
});

Any authenticated user can update any other user's profile by supplying a different userId in the request body. The authenticated user's identity must always come from the verified session token, never from client input.

// Safe - userId from verified session token only
app.put('/api/profile', requireAuth, async (req, res) => {
  const { name, bio } = req.body;
  await db.user.update({
    where: { id: req.user.id }, // from JWT/session, not from request
    data: { name, bio },
  });
  res.json({ success: true });
});

4. Missing Role Checks on Privileged Actions

AI often adds basic authentication but skips role-based access control. An endpoint that should be admin-only gets protected with only a login check.

// Vulnerable - any logged-in user can access admin data
app.get('/api/admin/analytics', requireAuth, async (req, res) => {
  // requireAuth checks the token but not the role
  const data = await db.getFullAnalytics();
  res.json(data);
});

Any user who creates an account can now access your full analytics data. Add an explicit role check, either in a middleware layer or in the route handler itself.

5. Mass Assignment

AI-generated update endpoints often pass the entire request body to the database without filtering which fields are allowed to be updated.

// Vulnerable - spreads all request body fields into DB update
app.put('/api/users/:id', requireAuth, async (req, res) => {
  const updated = await db.user.update({
    where: { id: req.params.id },
    data: { ...req.body }, // attacker can set role: 'admin', isVerified: true, etc.
  });
  res.json(updated);
});

An attacker can add "role": "admin" to their request body and escalate their own privileges. Always explicitly list which fields are allowed in an update operation.


Catch Access Control Gaps Automatically

Access control bugs are subtle and they do not throw errors in testing. An endpoint that is missing an ownership check will appear to work correctly in every test where the test user owns the resource. You only discover the vulnerability when an attacker accesses someone else's data.

SecurePilot scans for access control patterns in your API code: missing auth middleware, IDOR patterns where resource IDs are not cross-checked against the authenticated user, client-supplied user IDs used in database queries, and mass assignment vulnerabilities. Run it on your AI-generated routes before they go to production.

Scan your AI-generated code now, free

165+ security rules. Results in under a second. No sign-up, no install.

Scan My Code Free