Access control
Every scanner in this group works from one kind of evidence: a request sent by a principal who should have been refused, and the response that came back. The principal is anonymous, a second user, a regular user instead of an admin, or a client sending a field it was never meant to control. The scanner then reads the body, because a 200 on its own proves nothing.
How this group works
Four principals, three resources, one loop. Each step below is one scanner from the group sending its characteristic request. Watch which principal sends it, what comes back, and what in the response turns a reply into a finding.
1Three principals and three resources. Each scanner picks the principal that should be refused and sends the request a more privileged principal is allowed to send. The decision is always made on the response body, never on the status alone.
2IDOR. User B asks for task 42, which belongs to User A. A 200 is only a finding if the body carries User A's data, and only if an anonymous request for the same id was refused; otherwise the object is public and nothing is wrong.
3Privilege escalation. The regular user requests a path that matches an admin indicator. A 200 is the finding. With two accounts the scanner also compares the admin's and the regular user's replies to the same GET, and flags only when the admin's is more than 1.5 times larger and holds more records.
4Mass assignment. A bare body with one escalation field goes to every POST, PUT and PATCH endpoint. The finding needs a 2xx and the same field with the same value somewhere in the reply, however deep the envelope.
5Body param fuzzer. A write that User A really sent during the crawl is replayed with one field replaced. A database error pattern, a verbatim reflection, a 5xx on a wrong type, or a __proto__ key accepted without a 400 each make a finding.
6The static side. Route auth tracing reads the handler for a guard and follows it to its definition. The RLS policy analyzer reads the migrations; the RLS deep scanner asks the live table with the public anon key. When a DAST and a SAST finding of a paired category land on the same app, correlation raises both.
Scanners in this group
IDOR and cross-user BOLA
Why an unauthenticated swap is only a lead, harvesting User A's real ids, the two guards that kill false positives, and mutation read-back.
Row Level Security
The anon key is public, so a policy is the only thing between the internet and the table. Migration parsing on one side, live anon and cross-user queries on the other.
Route auth tracing
Guard names on word boundaries, lookups that are not authentication, and a language server following the guard to its definition.
Privilege escalation
Eight probes from the regular user's session: admin tables and routes, role self-elevation, the admin-vs-regular differential with its 1.5x rule, replaying the admin's writes, and RPC calls.
Mass assignment
One escalation field per request to every write endpoint, a reflection check that walks the whole JSON envelope, and the bare-body limit that keeps one Juice Shop challenge out of reach.
Body param fuzzer
Captured authenticated writes replayed with one JSON field swapped: SQL error patterns, verbatim reflection, 5xx on a wrong type, and a prototype-pollution key accepted without a 400.
At a glance
| Scanner | What it looks at | What it reports | Severity | Needs |
|---|---|---|---|---|
| IDOR scanner | Endpoints with ids; the ids User A owns, harvested during the crawl | User B reading or mutating User A's object; unauthenticated swaps as leads only | Medium to Critical | URL; credentials, a second account for cross-user; --probe-writes for the mutation path |
| RLS policy analyzer | Supabase migration SQL | Tables without Row Level Security or with permissive policies | Critical | Repository |
| RLS deep scanner | Live Supabase REST with the anon key and both sessions | Anonymous and cross-user reads and writes the policies should block | Critical | URL; Supabase URL and anon key found in the JS; credentials |
| Route auth analyzer | Every API route file and its handler; the guard's definition via LSP | Routes missing authentication or input validation | High | Repository; a language server for guard tracing (optional) |
| Privilege escalation scanner | Admin-looking tables and routes, protected endpoints, writes captured from User A, User A's owned ids, RPC names from the bundle | Regular user reaching admin data, elevating its own role, replaying admin writes, writing another user's row, calling RPC functions | Medium to Critical | URL; credentials; second account for the admin-vs-regular tests; Supabase for the table, row and RPC tests |
| Mass assignment scanner | Every POST, PUT and PATCH endpoint in the inventory | An escalation field accepted and reflected in the reply | High | URL only; --probe-writes when the bundle yields only GETs; session headers when logged in |
| Body param fuzzer | JSON bodies of successful writes captured during the authenticated crawl | SQL error, reflected XSS, type confusion 5xx, prototype pollution key accepted | Medium to Critical | URL; credentials (the authenticated crawl supplies the requests) |
Why this class matters
Access control bugs do not need a payload. The request is well formed, the server is working as written, and the only thing wrong is who was allowed to send it. Privilege escalation turns a free account into full admin access: every record, every setting, every delete, and new admin accounts for persistence. Mass assignment lets a client promote itself, zero a price or mark an order paid by adding a field. An IDOR hands one user another user's data by changing a number. None of these show up in a crash log.
Microsoft Exchange, ProxyLogon (2021). CVE-2021-26855 let attackers authenticate as the Exchange server, escalate to admin and install web shells across tens of thousands of organisations. GitHub (2012). Egor Homakov used a Rails mass assignment flaw to attach his SSH key to the Rails core repository by setting user_id, gaining commit access. HackerOne (2015). A mass assignment flaw allowed adding yourself as a member of any bug bounty program by manipulating group membership parameters.