OWASP A01
Testing for Broken Access Control
The most common serious finding in modern applications, and the one automation is least able to help with. Access control is a statement about intent, and intent cannot be fingerprinted.
- Tested across every role pair, not just admin versus user
- Includes tenant isolation in multi-tenant platforms
- Every finding proven by actually accessing the data
What broken access control looks like in a real application
A support agent opens a customer record by visiting /customers/48812. Changing the number to 48813 returns a different customer. The endpoint checked that the agent was logged in and never checked whether this agent was assigned to that customer. Nothing is misconfigured, no library is out of date, and no payload is malicious — the application is doing exactly what it was written to do.
This is why access control dominates real findings. It is not a bug in a dependency; it is a missing line of business logic, and there is no scanner signature for a line that was never written.
The broken access control variants we test for
- Horizontal escalation — reaching another user's data at the same privilege level, usually through enumerable identifiers
- Vertical escalation — a lower-privileged role reaching functionality reserved for a higher one
- Insecure direct object references across every identifier we can enumerate, including UUIDs, which are not an authorisation control
- Function-level authorisation gaps on endpoints the interface never exposes but the API still accepts
- Tenant boundary failures where a tenant identifier is taken from the request rather than derived from the session
- Forced browsing to pages and states that are hidden in the UI but not protected on the server
- Method-based bypasses where GET is protected and PUT, PATCH or DELETE are not
- Mass assignment allowing a request to set fields such as role, tenant or approval status
- Indirect access through exports, search indexes, notification payloads and cached responses that bypass the primary check
How we test for broken access control
Access control testing requires a credential matrix. We ask for one account per role, including the roles you consider uninteresting, then build a map of every action each role can legitimately perform. The test is systematic replay: take a request captured as role A and reissue it as role B, C and unauthenticated, then compare responses.
The number of tests scales with role pairs rather than roles, which is why an application with eight roles takes substantially longer than one with three. Skipping combinations is where most assessments quietly lose their value, so the report states which pairs were covered.
For multi-tenant platforms we run the same matrix across tenant boundaries, and extend it into asynchronous paths — background jobs, scheduled reports and webhooks — because those frequently execute with wider privileges than the request that triggered them.
Why scanners miss almost all of it
A scanner can tell that /customers/48813 returned HTTP 200. It cannot tell whether that response should have been authorised, because it has no model of who you are or what you are entitled to see. Detecting broken access control requires knowing the intended policy, and the intended policy exists only in your team's heads and in your specification.
This is the single strongest argument for manual testing, and the reason an access-control-free report on a role-based application should be treated as a red flag rather than good news.
How broken access control gets fixed
- Deny by default, and make authorisation a required argument of the data access layer rather than a decorator someone can forget
- Derive tenant and owner context from the session, never from a request parameter
- Centralise policy so a new endpoint inherits enforcement instead of reimplementing it
- Treat identifiers as public: unguessable IDs reduce enumeration but are not an authorisation control
- Add automated tests that assert each role cannot reach the other roles' resources, so the fix does not regress
Common questions
Why is broken access control ranked first in the OWASP Top 10?
Because it is both the most widespread and among the most damaging. It requires no special tooling to exploit, it is invisible to automated scanning, and a single missing check can expose every record in a system. OWASP moved it to the top position in the 2021 revision on the strength of how frequently it was found in tested applications.
Do random or UUID identifiers fix insecure direct object references?
No. They make enumeration harder, which raises the effort required, but they do not authorise anything. UUIDs leak through URLs, referrer headers, logs, exports, support tickets and shared links, and once an attacker holds one the missing authorisation check is still missing. Treat unguessable identifiers as a speed bump, not a control.
How many test accounts do you need from us?
One per role, including read-only, trial, suspended and support roles, plus two accounts in the same role so we can test access between peers. For multi-tenant systems we also need accounts in two separate tenants. Without peer and cross-tenant accounts, an entire class of finding cannot be tested.
How do you test access control in a multi-tenant SaaS platform?
We need accounts in at least two separate tenants, then replay every request captured in one tenant as a user of the other. Beyond the obvious endpoints we check exports, search, notifications, cached responses and background jobs, because those often derive tenant context differently from the main request path. We run our own multi-tenant platform, so this is the failure mode we know best.
Can you test access control without production data?
Yes, and we prefer it. Access control testing needs realistic data structure and role configuration, not real customer records. A staging environment seeded with representative synthetic data across multiple accounts and tenants produces the same findings with none of the risk. What matters is that roles and permissions mirror production exactly.
What is the difference between an authentication and an authorisation finding?
Authentication is about proving who you are; authorisation is about what that identity is permitted to do. A login bypass is an authentication finding. Being correctly logged in and still able to read another customer's invoice is an authorisation finding. The distinction matters because they are fixed in different places and authorisation failures are far more common.
Why do access control findings take longer to remediate?
Because the fix is usually architectural rather than local. Patching the one endpoint we demonstrated leaves the same gap on every other endpoint that was written the same way. The durable fix is to make authorisation a required part of your data access layer so a developer cannot ship an endpoint that forgets it, and that is a refactor rather than a patch.
Let's scope your infrastructure.
Tell us what you have built and what you are testing against. You will speak to a Lead Security Architect, not a sales desk, and you will get a written scope with a fixed price before any work begins.