Change one digit in an address and somebody else's invoice loads. Not a copy. Not a summary. Their invoice, in full, on your screen.
There is no malware in that story. No zero-day, no privilege escalation, no clever bypass. An API checked who the caller was, decided the caller was legitimate, and then handed over an object it never stopped to ask about. Was that object theirs? Nobody asked. That missing question has a name: Broken Object Level Authorization, BOLA for short, or IDOR to an older generation of testers. It sits at API1:2023, the number one risk in the OWASP API Security Top 10:2023. And most organizations keep shipping it.
Read that ranking again. The top API risk is not exotic. It is a check that was never written.
One endpoint, two questions
The mechanics are plain enough to write on a whiteboard. An endpoint accepts an object identifier — GET /api/invoices/1042 — verifies that the caller is authenticated, and returns the object. What it does not do is ask whether invoice 1042 belongs to that caller. The first question got answered. The second one never came up.
Those two questions sound alike, and that is part of the trouble. Authentication asks who you are. Authorization asks a narrower, harder thing: may this identity perform this action on this specific object? One question is about a person. The other is about a relationship between a person and a thing — this invoice, this order, this record — and relationships can't be settled once at a login screen. They have to be settled object by object, request by request.
So why does the first question get answered so reliably? Because frameworks make it trivial. Attach a JWT, verify the signature, done. The second question has no such luck. It is custom code, written on every endpoint, every method, every nested resource. Miss one, and the application is exposed.
The flaw maps to CWEs 285 and 639, and it survives quietly. Nothing in the request looks wrong. The caller is real, the token is valid, the object exists, the response is a success. Every part behaves, except for the ownership check that wasn't there.
Scale turns that small omission into an enterprise problem. APIs now carry the majority of enterprise application traffic, and attackers followed it. The Verizon 2025 Data Breach Investigations Report confirmed API-related incidents have grown to a greater share of web-application breaches, validating Gartner's prediction that by 2025 API attacks would become the most frequent attack vector.
GraphQL hands over the corridor
REST, at least, makes an attacker walk from door to door: each resource has its own endpoint, its own path. GraphQL hands over a corridor instead. A single endpoint serves every data type through a flexible query language, and resolvers traverse object relationships — user to orders to payment methods — at the caller's direction. The caller chooses the route. The API follows it.
Now put the missing check inside that design. If each resolver doesn't enforce per-node ownership checks, one carefully crafted query walks the entire relationship graph: your own user node, then the edge into another tenant's organization, then down into their invoices. At every step, the API "works as designed." The authorization model was designed wrong.
Notice where the failure actually sits. Not inside any single resolver. In the assumption between them: each step trusts that some other step checked the thing nobody checked, so the query passes from node to node carrying an approval nobody ever gave. A corridor is only as safe as the doors along it, and here the doors were assumed, not built.
Salt Security's research measures what that costs. In its 1H 2026 State of API Security report, 94% of organizations experienced an API security incident in the prior 12 months. And 99% of attacks used authenticated access.
Sit with that number.
The attacker had valid credentials or tokens, so perimeter authentication provided no protection at all. That is exactly what makes BOLA dangerous: it lives behind the login, past the point where the defences most teams rely on have already done their job and stood down. An earlier edition of Salt's research found malicious API calls up 348% in a six-month window, and attributes roughly 40% of API attacks to BOLA specifically. Not a fringe technique. A large share of the whole problem is this one missing check, repeated.
The 1H 2026 edition adds two findings that belong together. 47% of organizations slowed or halted AI application deployments over API security concerns. And 49% lack visibility into machine-to-machine API traffic, the shadow channel where agentic AI systems increasingly operate. Half the traffic, unseen. Nearly half the AI roadmap, paused over it.
Salt Security CEO Roey Eliyahu called API security "a top business priority" as "API sprawl, AI adoption, and threat sophistication" create "the perfect storm for API risk." Eric Schwake of Salt Security added that teams are "waking up to the fact that API sprawl is creating real security and compliance risk." Regulators point the same way: PCI DSS 4.0, SOC 2, ISO 27001:2022 and HIPAA all increasingly demand demonstrable authorization controls and API inventory.
Put the check in one place
Start with the check itself. Every endpoint, every method, every resolver must answer the ownership question before returning or mutating data: does this authenticated identity have rights to this specific object? A read that leaks and a write that alters are two doors into the same room.
Where that check lives matters almost as much as whether it exists. Centralize it in a policy layer rather than scattering it across controllers, because scattered checks are where endpoints get missed. One place, one pattern, applied the same way every time — that is what makes a check dependable rather than hopeful.
A centralized chokepoint carries a second benefit: a new service inherits the checks instead of re-implementing them, so the policy survives team turnover, rewrites and acquisitions.
Then make identifiers unguessable. Sequential IDs like /invoices/1042 are an invitation, because the next invoice is just the next number up. UUIDs don't repair a missing authorization check — an unguessable identifier in front of an unchecked endpoint is still an unchecked endpoint. What they do is raise blind enumeration from trivial to infeasible. The check stays the fix.
Test authorization like it matters, because BOLA is uniquely testable. Automated tests should exercise every endpoint as User A attempting to access User B's objects — cross-user, cross-tenant, cross-role. The oracle is simple: did the response contain someone else's data? Either User A got User B's object or they didn't. And the coverage requirement is total: BOLA only needs the rest.
Discovery comes before all of it, though. The 85% inventory-confidence gap is a prerequisite failure: continuous discovery from gateway logs, code scanning and runtime traffic has to precede any control, because unlisted APIs are by definition unprotected — and the unknown APIs are where BOLA lives longest. You can't centralize a policy over a surface you haven't mapped, or test endpoints you haven't found. Inventory first, then the check, then the tests.
Two more layers earn their place. Runtime API protection platforms — Salt Security, Noname Security, Traceable, and gateway-native options — learn per-endpoint behavior baselines and flag anomalies: a user suddenly enumerating thousands of object IDs, a token touching object types it never touched before. They detect BOLA exploitation even when the code fix hasn't shipped, functioning as a virtual patch — time to fix the code properly instead of in a panic. And rate-limit and monitor object-ID endpoints aggressively, because exploitation at scale looks like sequential or bulk ID access. These controls pair naturally with faster, automated detection inside the SOC and runtime protection inside the application itself.
For GraphQL specifically, the corridor needs its own rules. Add depth and complexity limits on queries. Enforce per-field and per-node authorization in every resolver, because the graph is traversed node by node and the check has to travel with the traversal. Disable introspection in production. And use persisted-query allowlists for high-sensitivity operations. None of this is exotic. All of it is routinely skipped.
Why nobody owns the checklist
BOLA persists for structural reasons technology alone won't fix. Microservice architectures multiply endpoints, and every endpoint is another place authorization can be forgotten. The surface grows by design, and each addition is a fresh opportunity to answer the first question and skip the second.
Frontend-driven development pushes the same way. It encourages fine-grained REST and GraphQL endpoints optimized for UI convenience, each one a new authorization surface. An endpoint shaped to make a screen easier to build is still obliged to ask who those objects belong to. Convenience doesn't waive the question. It multiplies how often the question needs asking.
And the shift to AI agents consuming APIs machine-to-machine is expanding the attack surface faster than teams can inventory it — remember, 49% of organizations admit they cannot see that traffic at all. The agents add volume, speed and new routes on top of an inventory that was already incomplete, and the same APIs are a collection target for state-level espionage programs with long time horizons, the kind of adversary content to work slowly through exactly the traffic nobody is watching.
There is a reason this vulnerability outlives every remediation program thrown at it. It is not a coding bug in the usual sense. Nothing crashes. Nothing logs an error. The API returns a cheerful 200 with somebody else's data inside it, and every control that asks "is this request well-formed?" says yes. Only the control that asks "is this object yours?" would say no — and that is the control each team quietly assumes another team wrote.
That assumption is the whole story, really. Not malice, not incompetence. A handoff that never happened, repeated across enough endpoints and enough teams that it becomes the normal state of things.
The deeper cause is organizational. Authorization is a product requirement, not a security feature bolted on afterward. Until product teams treat "User A cannot see User B's data" as a launch-blocking acceptance criterion, BOLA will keep appearing in penetration-test reports and breach disclosures. The digit will keep changing. And somebody else's invoice will keep loading.
Sources
- Salt Security Blog — 1H2026 State of API Security Report: API Attacks Surge
- eSecurity Planet — State of API Security Report: AI Slows as 94% Face API Attacks (1H 2026)
- IT Security Guru — Salt Security 1H2026 State of API Security Report Highlights Need for Stronger API Security Posture
- Salt Security Blog — BOLA Attacks: A Growing Threat
- Salt Security Blog — State of API Security Report Q1 2025
- AppScaleLab — What Is Broken Object Level Authorization (BOLA)?
- OWASP — API Security Top 10:2023, API1:2023 Broken Object Level Authorization