Back to Blog
Security

IDOR and Broken Access Control: The #1 Vulnerability Hiding in AI-Generated Apps

Broken access control is OWASP's #1 risk and appears in the majority of AI-generated apps. Learn how IDOR and BOLA vulnerabilities slip into vibe-coded APIs, see real examples, and get a step-by-step fix and testing playbook.

June 6, 2026
Belsoft Team
11 min read

Broken Access Control Is Now the #1 Security Risk

When OWASP last updated its Top 10, broken access control jumped to the number one position—and for good reason. OWASP found access control failures in **94% of the applications they tested.** It remains the single most common, most exploited class of web vulnerability, and AI-generated code is making the problem dramatically worse.

The most common form of broken access control is IDOR: Insecure Direct Object Reference. It is cheap to introduce, easy to miss in review, and devastating when exploited. And it is exactly the kind of bug AI assistants produce by default.

What Is IDOR (and How It Relates to BOLA)?

IDOR is an access control flaw where an application exposes a reference to an internal object—a database record, a file, a user ID—without verifying that the requester is actually allowed to access it.

The classic example: you log in and visit `/api/invoices/1043`. You see your invoice. Then you change the number to `/api/invoices/1044` and see *someone else's* invoice. The API authenticated you (it knows who you are) but never authorized you (it never checked whether this invoice is yours).

You will also see this called **BOLA (Broken Object Level Authorization)**—the term OWASP uses in its API Security Top 10. IDOR and BOLA describe the same underlying failure: missing per-object ownership checks.

Why AI-Generated Code Is So Prone to IDOR

AI models are trained on mountains of tutorial code, and tutorials almost always skip authorization to stay readable. So when you ask an assistant to "build an endpoint that returns an order by ID," it gives you exactly that—and nothing more:

// ❌ AI-generated: authenticated, but NOT authorized

app.get('/api/orders/:id', requireAuth, async (req, res) => {

const order = await Order.findById(req.params.id)

res.json(order) // Returns ANY order to ANY logged-in user

})

The code looks complete. It compiles, it passes a happy-path test, and it ships. But there is no check that `order.userId` matches `req.user.id`. Every authenticated user can read every order by walking the IDs.

This is the AI security paradox in miniature: the code works, so it feels done—while a critical access control hole sits in plain sight.

A Real-World IDOR: Cross-Tenant Data Exposure

In 2026, a broken access control advisory in a popular AI application showed the pattern at scale. Authenticated teams could access applications belonging to *other* teams simply by supplying a foreign `appId`. The API correctly validated each team's token, but never verified that the requested application actually belonged to the authenticated team—leading to cross-tenant data exposure.

That is the multi-tenant nightmare: one missing ownership check turns a per-user bug into a whole-company data breach.

Spotting IDOR in Your Codebase

Look for any endpoint that takes an ID from the request and fetches a record without scoping it to the current user. Compare the two patterns below.

**Vulnerable:**

// ❌ No ownership check

app.get('/api/documents/:id', requireAuth, async (req, res) => {

const doc = await Document.findById(req.params.id)

res.json(doc)

})

**Fixed:**

// ✅ Query scoped to the authenticated user

app.get('/api/documents/:id', requireAuth, async (req, res) => {

const doc = await Document.findOne({

_id: req.params.id,

ownerId: req.user.id, // the ownership check

})

if (!doc) return res.status(404).json({ error: 'Not found' })

res.json(doc)

})

How to Fix IDOR: The Ownership Check Pattern

#

1. Always Ask "Does This User Own This Resource?"

Before returning any object tied to a user, tenant, or organization, verify ownership. Make it a non-negotiable rule for every handler that accepts an ID.

#

2. Centralize Authorization Logic

Scattered, copy-pasted permission checks are where IDOR creeps back in. Put authorization in one middleware or policy layer so every route enforces it the same way. Inconsistent checks are the root cause of most access control oversights.

#

3. Use Unguessable Identifiers

Sequential integer IDs make enumeration trivial. Prefer UUIDs or other random identifiers so attackers cannot simply increment a number—though remember this is defense in depth, not a substitute for a real ownership check.

#

4. Scope Every Database Query to the User

The most robust fix is to make it *impossible* to fetch another user's data: include the owner constraint directly in the query (`ownerId: req.user.id`) rather than fetching first and checking later.

How to Test for IDOR Before You Deploy

IDOR only shows up when the app is running, which is why static review alone misses it. Test it dynamically:

  • Create two test accounts, A and B.
  • As user A, note the IDs of your resources.
  • As user B, request user A's resource IDs directly.
  • If B gets A's data, you have an IDOR. Repeat for every endpoint that accepts an identifier.
  • Automating this cross-account probing is exactly the kind of dynamic testing that catches access control bugs traditional unit tests sail right past.

    How DeployReady Detects Broken Access Control

    DeployReady probes your running application, not just your source. It exercises authentication and authorization flows, attempts to access resources across user boundaries, checks for exposed admin routes, and flags endpoints that return data without proper ownership checks.

    npx deployready@latest analyze ./my-app

    ✦ Testing localhost app...

    🔴 CRITICAL: /api/orders/:id returns records without ownership check (IDOR)

    🔴 CRITICAL: Admin route /admin/users reachable without authorization

    🟡 WARNING: Sequential integer IDs enable resource enumeration

    Production Readiness Score: 38 / 100

    You get the finding, the affected route, and the fix guidance before the bug becomes a breach.

    The Bottom Line

    Broken access control is the #1 OWASP risk, IDOR is its most common form, and AI assistants generate it by default because they copy authorization-free tutorial code. The fix is simple to state and must be applied everywhere: authenticate the user, then authorize the object. Scope every query, centralize your checks, and test across accounts before you ship.

    npx deployready@latest analyze .

    Resources

  • OWASP Top 10 — Broken Access Control: https://owasp.org/Top10/A01_2021-Broken_Access_Control/
  • OWASP API Security Top 10 (BOLA): https://owasp.org/www-project-api-security/
  • CWE-639: Authorization Bypass Through User-Controlled Key: https://cwe.mitre.org/data/definitions/639.html
  • ---

    **Not sure if your AI-generated API has an IDOR hole?** [Scan it with DeployReady](https://www.npmjs.com/package/deployready) or [book a security check](https://www.belsoftsolutions.com/meeting).

    About the author

    The DeployReady team creates production-readiness tools for developers building with AI and building in general. We're passionate about security, performance, and shipping code with confidence.

    Ready to check your app's production readiness?

    DeployReady scans your code and running application to find security vulnerabilities, performance issues, and deployment risks—before they reach production.