Broken Access Control Checklist · Find and Fix OWASP A01

Quick answer: Broken access control (OWASP A01) occurs when an app fails to restrict users from accessing data or functions they do not own. To fix it, you must implement server-side ownership checks, enforce role-based access control (RBAC), and enable Row-Level Security (RLS). Never rely on the UI to hide buttons.

By Paula C · Kraftwire Software

· 9 min read

Broken access control (OWASP A01) is a vulnerability where an application fails to enforce restrictions on what authenticated users are allowed to do. To fix it, you must implement server-side ownership checks on every record, enforce role-based access control (RBAC) for all privileged functions, and enable Row-Level Security (RLS) at the database layer. Never rely on the UI to hide buttons or obfuscate URLs as a security measure.

While the average security score for these apps is 85 out of 100, the presence of critical authorization gaps in nearly a third of projects highlights a systemic issue in vibe-coded development: AI tools excel at building features but often omit the invisible security logic required to protect user data.

What Is Broken Access Control?

Broken access control, or authorization failure, occurs when a web application grants access to content and functions to users who should not have them. It is currently ranked as the #1 risk in the OWASP Top 10 (A01) because it is both widespread and difficult to detect with automated tools alone.

Unlike authentication (which asks "Who are you?"), access control asks "What are you allowed to do?". When this breaks, a user might:

  • Access another user's private data (Horizontal Privilege Escalation).
  • Access administrative functions without being an admin (Vertical Privilege Escalation).
  • Modify or delete records they do not own.
  • Bypass access control checks by modifying the URL, internal application state, or the HTML page.

For developers using AI tools like Lovable, Bolt.new, or Cursor, this is the most dangerous category of risk. AI models often generate "happy path" code that works perfectly for the intended user but lacks the WHERE user_id = current_user clauses or middleware checks needed to block unauthorized actors. For a broader look at how these risks manifest in modern stacks, see our OWASP Top 10 for AI-built apps.

Real-World Examples in Vibe-Coded Apps

Vibe-coding · building apps through high-level AI prompting · often results in architectural gaps.

1. Insecure Direct Object References (IDOR)

This is the most common form of A01. An app might display a user's profile at example.com/api/users/501. If an attacker changes the ID to 501 to 502 and successfully views another user's private data, the app has an IDOR vulnerability. AI-generated code often fetches records by ID without verifying that the owner_id matches the session.user_id.

2. UI-Only Admin Protection

Many AI-built apps use "security through obscurity" by simply hiding the /admin link in the navigation bar for non-admin users. However, if the underlying API endpoint /api/admin/delete-user does not verify the user's role on the server, any user can trigger the action by sending a direct request. We discuss this further in our guide on architecture security risks.

3. Missing Row-Level Security (RLS)

In platforms like Supabase, the "anon" key is public. If you do not enable RLS on your tables, anyone with your project URL and anon key can query your entire database. You can learn how to lock this down in our Supabase security checklist.

4. Client-Side Role Manipulation

If your application stores the user's role (e.g., role: "user") in local storage or an unverified cookie, an attacker can simply change that value to "admin" in their browser console. If the server trusts this client-provided value, the attacker gains full privileges. Always verify roles using a JWT debugger to ensure claims are signed and untampered.

The Broken Access Control Checklist

Use this checklist to audit your application before shipping. Every "Yes" should be backed by a server-side implementation, not just a frontend UI change.

Object-Level Access (IDOR Prevention)

  • Does every API request that fetches a resource verify the requester's ownership?
  • Are you using UUIDs instead of sequential integers (1, 2, 3) for record IDs to prevent enumeration?
  • Are file uploads and downloads protected by the same ownership logic?
  • Do "List" endpoints automatically filter out records not belonging to the authenticated user?

Function-Level Access (RBAC)

  • Is there a server-side middleware that checks roles for every privileged route?
  • Are administrative API endpoints completely inaccessible to non-admin tokens?
  • Does the application follow the "Principle of Least Privilege" (users only have access to what they absolutely need)?
  • Are sensitive actions (like changing a password or deleting an account) protected by a re-authentication or CSRF check? (See our CSRF security headers guide).
  • Is the default state for any new endpoint "Deny All" until access is explicitly granted?

Data Layer Security

  • Is Row-Level Security (RLS) enabled on every single table in your database?
  • Do RLS policies use auth.uid() or equivalent server-side identity markers?
  • Have you tested your "anon" key against your API to ensure it cannot fetch sensitive rows?
  • Are you avoiding the use of "service_role" keys in any client-side code or edge functions reachable by users?
  • Are database views also protected by the same access control logic as the underlying tables?

Session and Token Integrity

  • Are JWTs verified on the server for signature, expiration, and issuer on every request?
  • Is the user's role fetched from a trusted source (the database or a signed token claim), never the request body?
  • Does logging out invalidate the session on the server, not just delete the token from the browser?
  • Are you using HttpOnly and Secure flags for cookies to prevent token theft?
  • Do you have a mechanism to revoke access immediately for compromised accounts?

How to Test for Broken Access Control

The Two-Account Test

  • Create two accounts: User A and User B.
  • Log in as User A and create a private record (e.g., a note or an invoice).
  • Copy the ID or URL of that record.
  • Log in as User B and try to access that ID or URL.
  • If User B can see or edit the record, you have an IDOR vulnerability.

Direct API Testing

Don't just test the browser; test the API. Use a tool like curl to attempt to reach protected endpoints without a token, or with a low-privilege token.

A secure app will return a 403 Forbidden or 401 Unauthorized. If it returns a 200 OK, your function-level access control is broken.

Testing Supabase RLS

If you are using Supabase, you can test for missing RLS by querying your tables using the public anon key from your terminal:

If this returns data that doesn't belong to the "public" role, your RLS policies are either missing or too permissive. For more on this, see RLS policies explained.

How to Fix Broken Access Control

Fixing A01 requires a "Defense in Depth" approach. Do not rely on a single check; enforce authorization at every layer of the stack.

  • Enforce Ownership in the Query: Never fetch a record by ID alone. Always include the user's ID in the WHERE clause. This ensures that even if an attacker guesses an ID, the database returns nothing because the ownership doesn't match.
  • Implement Server-Side Middleware: Use middleware to check permissions before your route handler even runs. This prevents "forgotten" checks in individual functions.
  • Use UUIDs: While not a primary security fix, using UUIDs makes it impossible for attackers to "guess" the next record ID. This prevents mass scraping of data.
  • Centralize Authorization Logic: Don't scatter if (user.isAdmin) checks throughout your codebase. Use a centralized library or service to handle permission logic so it can be updated in one place.
  • Enable RLS as a Backstop: Even if your API code has a bug, Row-Level Security at the database level can prevent data leaks. It is your last line of defense.

Automated Detection and Monitoring

While manual testing is vital, automated tools can catch the "low-hanging fruit" of broken access control, such as missing security headers, exposed API keys, and weak RLS configurations.

SimplyScan provides a comprehensive health check for vibe-coded apps. In ~30 seconds, it scans for:

  • Exposed sensitive API keys that could lead to privilege escalation.
  • Missing or weak Supabase RLS policies.
  • Broken authentication patterns and missing security headers.
  • Environment variable leaks.

Optimizing your access control logic doesn't just improve security; it improves performance.

After running an automated scan, use our vibe coding security checklist to perform the manual deep-dives required to fully close out OWASP A01. For ongoing protection, SimplyScan Pro offers monitoring and scheduled rescans to ensure that a new AI-generated feature doesn't accidentally reopen a security hole you previously closed.

FAQ

What is the difference between broken access control and broken authentication?

Authentication (OWASP A07) is the process of verifying a user's identity (e.g., logging in with a password). Access control (OWASP A01) is the process of verifying what an identified user is allowed to do. You can have perfect authentication but still have broken access control if a logged-in user can access another user's data.

What is an IDOR vulnerability?

IDOR stands for Insecure Direct Object Reference. It occurs when an application uses an identifier (like a database ID) to access an object directly without checking if the user has permission. For example, changing ?id=123 to ?id=124 in a URL to see someone else's private profile is a classic IDOR.

Is broken access control the most common web vulnerability?

Yes. According to the most recent OWASP Top 10 data, Broken Access Control (A01) is the most frequently occurring category of vulnerability in modern web applications.

How do I test for privilege escalation?

To test for vertical privilege escalation, attempt to access admin-only URLs or API endpoints using a standard user account. To test for horizontal privilege escalation, use two standard accounts and try to access or modify Account A's data while logged into Account B.

What is missing function-level access control?

This occurs when an application fails to verify a user's permissions before executing a specific function. A common example is an admin panel that is hidden in the UI but remains accessible via a direct URL (e.g., /admin/delete-all) to any authenticated user who knows the path.

Can RLS alone prevent broken access control?

While Row-Level Security (RLS) is an incredibly powerful tool for preventing data leaks at the database level, it is not a complete solution. RLS does not protect against function-level failures (like a user triggering a server-side email blast) or logic errors in your application code. Use RLS as one layer of a multi-layered security strategy.

Frequently asked questions

What is the difference between broken access control and broken authentication?

Authentication (OWASP A07) verifies who a user is (login). Access control (OWASP A01) verifies what they can do. An app has broken access control if a logged-in user can read another user's data or access admin functions they aren't authorized for. Both are critical but distinct layers of security.

What is an IDOR vulnerability?

IDOR (Insecure Direct Object Reference) is a type of broken access control where an attacker changes a resource ID (like a user ID in a URL) to access data they don't own. The fix is to always verify ownership on the server using the authenticated user's ID in the database query.

Is broken access control the most common web vulnerability?

Yes, Broken Access Control is currently the #1 risk on the OWASP Top 10. It is extremely common in AI-built apps because code generators often focus on functionality and UI while skipping the complex, invisible server-side authorization logic required to keep data private.

How do I test for privilege escalation?

Test for vertical escalation by trying to reach admin routes with a standard user account. Test for horizontal escalation by using two different user accounts and attempting to access Account A's private records while logged into Account B. Always test the API endpoints directly, not just the UI.

What is missing function-level access control?

It is a failure to check a user's role before executing a specific action. For example, an app might hide the 'Delete User' button from non-admins but still allow any logged-in user to call the `/api/admin/delete` endpoint. Security must be enforced at the API level, not the UI level.

Can RLS alone prevent broken access control?

RLS is a powerful backstop at the database layer, but it isn't a silver bullet. It doesn't protect against application-level logic errors, unauthorized API calls that don't hit the database, or unverified JWT claims. Use RLS alongside server-side middleware for true defense in depth.

Related guides

  • React Security Checklist: 10 Vulnerabilities to Fix Before Launch · React apps are client-side, making every secret and route guard visible to users. To secure your app before launch, you must move API keys to the server, sanitize HTML with DOMPurify, validate user-provided URLs, and enforce backend authentication for every sensitive request rather than relying on frontend logic.
  • A Security Headers Checklist for AI-Built Apps · A security headers checklist for 2026 must include Content-Security-Policy (CSP), HSTS with preloading, X-Content-Type-Options, X-Frame-Options, and Referrer-Policy. These headers prevent XSS, clickjacking, and data leaks. SimplyScan's data shows 33% of AI-built apps have high-severity issues, often due to missing these essential browser-level protections.
  • Bolt.new Security Guide: 7 Vulnerabilities to Fix Before Launch · Bolt.new apps often ship with critical flaws like API keys bundled in client JavaScript and missing Supabase RLS policies. To secure your app, move secrets to server-side functions, scope RLS to auth.uid(), and enforce server-side authentication. SimplyScan finds these vulnerabilities in 30 seconds, helping you ship safely.
  • Can ChatGPT and Claude Find Your App? A Guide to AEO · Answer Engine Optimization (AEO) determines whether ChatGPT, Claude, Perplexity, and Google's AI Overviews can crawl and cite your app. Most AI-built apps fail by blocking AI crawlers in robots.txt or serving JavaScript-only shells. Fix this by allowing GPTBot and ClaudeBot, serving real HTML, and adding llms.txt plus JSON-LD structured data.

All security guides · Free security tools · Platform scanners · Security checklist