DEV Community

Cover image for Business Logic Flaws Don't Fail Scans: They Pass Them. Here's Why.
Jigar Shah
Jigar Shah

Posted on

Business Logic Flaws Don't Fail Scans: They Pass Them. Here's Why.

TL;DR: Automated scanners are built to catch malformed input. Business logic flaws like BOLA, IDOR, and access control bypass are made entirely of well-formed requests. A scanner checking syntax has nothing to flag, which is why these vulnerabilities routinely survive a clean scan report and show up in production instead.

The scan that comes back clean

A team runs a security scan against their API. The report comes back with a handful of minor findings, nothing critical. Three weeks later, a security researcher (or worse, an attacker) demonstrates that changing a single number in a request URL lets any authenticated user pull another customer's invoice history.

The scan did not miss this because the tool was poorly configured. It missed it because the request that exposes the vulnerability is, from a technical standpoint, completely valid. Correct syntax. Correct authentication token. Correct endpoint. The only thing wrong with it is that the user should not have been allowed to ask for that specific object, and nothing in the request itself signals that.

This is the structural reason business logic flaws pass scans instead of failing them.

Why pattern matching works for some things and not others

Most automated scanning is built around pattern recognition. The scanner knows what a SQL injection payload looks like, what an XSS string looks like, what a malformed header looks like. It sends known-bad patterns at an endpoint and checks whether the server responds in a way that suggests the pattern succeeded.

This approach works well for vulnerability classes defined by malformed or malicious input. It does not work for vulnerability classes defined by valid input used in an unauthorized way. There is no pattern to match, because the request is not the problem. The relationship between the requester and the resource is the problem, and that relationship is something only the application's own authorization logic understands.

A scanner has no model of which user is supposed to access which object. It has no concept of role hierarchy, ownership, or the difference between "this user can view orders" and "this user can view this specific order." Pattern matching cannot evaluate a rule it was never given.

BOLA: requesting someone else's object, correctly

Broken Object Level Authorization sits at the top of the OWASP API Security Top 10 because it is both common and structurally invisible to traditional scanning. The mechanism is simple: an API endpoint accepts an object identifier in the request, fetches the corresponding object, and returns it, without confirming that the requesting user actually owns or has permission to access that specific object.

The request itself looks identical whether the user is requesting their own data or someone else's. Same endpoint, same method, same header structure. The only variable is the ID value, and changing an ID is not something a syntax-focused scanner treats as suspicious. It is, after all, just a number in a URL.

IDOR: the same flaw with a more familiar name

Insecure Direct Object Reference, formally classified as CWE-639, describes essentially the same mechanism as BOLA under an older and more widely recognized name. A resource is referenced directly through an identifier the client controls, and the server trusts that identifier without independently checking access rights.

Teams sometimes believe switching from sequential numeric IDs to UUIDs solves this. It does not. A UUID is harder to guess, which reduces the odds of a random unauthorized request succeeding. It does nothing to address the underlying problem, which is the absence of an authorization check. An attacker who obtains one valid UUID, through a leaked link, a referral parameter, or a previous interaction, can still access that object freely if the authorization check was never there.

Access control bypass through role assumption

A more advanced version of the same category involves privilege escalation through endpoints that assume role consistency rather than verifying it on each request. A user authenticated as a standard role calls an endpoint or modifies a request parameter that was built for an administrative role, and the endpoint, having authenticated the session, does not separately confirm that the session holder has administrative permission for that specific action.

This class of flaw is particularly difficult for automated tools because exploiting it requires understanding what a privileged action looks like in the first place, then constructing a request that a standard scan would have no reason to attempt. A scanner crawling an API does not know which endpoints are administrative unless that information is documented, and documentation is precisely what attackers rely on teams forgetting to restrict access to.

What actually catches these flaws

Catching business logic vulnerabilities requires behavioral validation rather than pattern matching. That means testing with awareness of session state, comparing what one authenticated user can access against what a different authenticated user with different privileges can access, and evaluating whether the application's authorization logic actually enforces the boundaries it claims to enforce.

This is meaningfully harder than syntax checking. It requires the testing tool to operate within an authenticated session, understand the relationship between users and objects in the application's data model, and execute multi-step sequences that reveal authorization gaps rather than single requests that reveal malformed input handling.

ZeroThreat's business logic flaw detection is built around this distinction. Rather than matching known-bad patterns, it analyzes behavior across authenticated sessions to identify where access control assumptions break down between users and roles. Combined with authenticated API scanning that operates within recorded session state, this approach tests the relationship between requester and resource, which is the actual location of a BOLA or IDOR vulnerability, rather than testing the request in isolation.

Common misconceptions worth correcting

A few assumptions show up repeatedly on teams that have not yet encountered this category of finding.

"We have authentication, so we're covered." Authentication confirms identity. It says nothing about authorization, which governs what an authenticated identity is permitted to access. These are different controls, and a system can have strong authentication with no meaningful authorization checks at all.

"Our IDs are UUIDs, so this doesn't apply to us." Unguessable identifiers reduce exposure to random scanning. They do not address the absence of an access control check, and any identifier that leaks through a referral link, a shared document, or a previous API response remains exploitable.

"We ran a penetration test last year and it was clean." Business logic flaws are introduced continuously as new endpoints and roles are added. A point-in-time test reflects the application as it existed at that point in time, not the application as it exists after the next six feature releases.

The takeaway

A clean scan report is not the same as a clean application. Scanners are good at finding what is wrong with a request. They are not built to evaluate what is wrong with a relationship between a user and the data they are requesting. Closing that gap requires testing that understands roles, sessions, and ownership, not just syntax.

Top comments (0)