• Agents
  • Docs
  • Pricing
  • Blog
Log in
Get started

Security for apps built with AI. Paste a URL, get a report, fix what matters.

Product

  • How it works
  • What we find
  • Pricing
  • Agents
  • MCP Server
  • CLI
  • GitHub Action

Resources

  • Blog
  • Docs
  • FAQ
  • Glossary

Security

  • Supabase Security
  • Next.js Security
  • Lovable Security
  • Cursor Security
  • Bolt Security

Legal

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • Imprint
© 2026 Flowpatrol. All rights reserved.
Home/What We Find/Broken Access Control
CWE-639CWE-284CWE-862OWASP #1

Broken Access Control IDOR, Missing RLS & Privilege Escalation

The #1 web vulnerability worldwide, according to OWASP. AI tools generate code that works — but they almost never check who's asking. If your app fetches data by ID without verifying ownership, anyone can see everyone's data.

What is broken access control?

Access control means enforcing rules about who can see or change what. Broken access control is when those rules are missing, incomplete, or bypassable. A user can view another user's profile. A member can hit admin endpoints. A customer can modify someone else's order by changing an ID in the URL.

It's been the #1 vulnerability category in the OWASP Top 10 since 2021. Not because it's complicated to fix — but because it's easy to forget. Every endpoint needs its own check. Miss one, and the whole boundary breaks.

What it looks like in code

Here's a typical API route generated by an AI tool. It fetches a user by the id parameter from the URL — but it never checks whether the person making the request is allowed to see that data.

Vulnerable — no ownership check
// app/api/users/[id]/route.ts
export async function GET(req, { params }) {
  const { id } = params;

  // Fetches ANY user by ID — no ownership check
  const user = await db.query(
    'SELECT * FROM users WHERE id = $1',
    [id]
  );

  return Response.json(user);
}
Fixed — scoped to the authenticated user
// app/api/users/[id]/route.ts
export async function GET(req, { params }) {
  const session = await getSession(req);
  const { id } = params;

  // Only return data if the requesting user owns it
  const user = await db.query(
    'SELECT * FROM users WHERE id = $1 AND user_id = $2',
    [id, session.user.id]
  );

  if (!user) return new Response(null, { status: 404 });
  return Response.json(user);
}

The fix adds two lines: get the session and filter by the authenticated user's ID. That's it. But AI tools almost never generate that second WHERE clause unless you explicitly ask for it.

Why AI tools generate this

Access control bugs aren't accidents. They're a predictable result of how AI code generation works.

  • They optimize for "it works." AI generates code that fulfills the prompt — fetch a user, display a profile, list orders. The happy path works. But there’s no concept of "this user shouldn’t see that data." Access control is a constraint the prompt almost never specifies.
  • Authorization is contextual. Unlike input validation (which has clear patterns), access control depends on your app’s business logic. Who can see what? Which roles exist? AI tools don’t have that context, so they skip it entirely.
  • Defaults are wide open. Supabase tables ship with RLS disabled. Next.js API routes have no built-in auth middleware. Express endpoints are public by default. AI tools use these defaults and move on.

Common patterns

Sequential ID enumeration

User IDs like /api/users/1, /api/users/2, /api/users/3. Change the number, get someone else’s data. AI almost always uses auto-incrementing IDs without ownership checks.

Missing RLS on Supabase tables

Row Level Security is disabled by default. AI tools create tables and insert data without ever running ALTER TABLE ... ENABLE ROW LEVEL SECURITY. Every row is readable by every user.

Privilege escalation via role field

Registration endpoints that accept a role field in the request body. Send {"role": "admin"} during signup and grant yourself full access. Mass assignment at its worst.

Unprotected admin endpoints

Admin routes like /api/admin/users or /api/settings that check if you’re logged in but never check if you’re actually an admin. Any authenticated user can access them.

How Flowpatrol detects it

Flowpatrol doesn't just check for missing auth headers. It tests actual access boundaries the way a real attacker would.

  1. 1Creates multiple test accounts. Flowpatrol registers or logs in as two separate users with different roles and permissions.
  2. 2Maps every endpoint. It crawls your app, captures every API call, and builds a map of your entire data surface.
  3. 3Cross-tests access. It takes User A’s session and tries to access User B’s data. Every endpoint, every ID, every role boundary.
  4. 4Flags what leaks. If User A can read, modify, or delete User B’s data, you get a finding with the exact endpoint, payload, and response.

No guesswork. No theoretical warnings. You get proof — specific endpoints where access control is broken, with the exact requests and responses.

Check your app for access control flaws.

Paste your URL. Flowpatrol tests every endpoint with multiple users and tells you exactly what leaks.

Try it free