Automated Multi-User BAC & IDOR Testing for Burp Suite
Multi-User Broken Access Control (BAC) & IDOR Testing Extension for Burp Suite
TokenTwin Checker automates authorization testing across multiple authenticated users. It replays the same request under different authentication contexts and tells you — with an authorization-aware verdict — whether one identity can reach another identity's data. It is built for security researchers and bug bounty hunters chasing Broken Access Control, IDOR, and horizontal / vertical privilege escalation.
- Tab-switch rendering fixed for real. The extension now forces a full revalidate + repaint whenever its tab becomes visible, and its root panel is opaque — this clears the ghosting where the previous Burp tab showed through and components painted "one at a time" on tab switch, especially after long sessions.
- EDT no longer flooded. Result rows are added to the table in coalesced batches and the progress bar collapses to its latest value, instead of one Swing event per request — a large run can no longer starve UI painting.
- Bounded, snappy table. The results table is capped (oldest rows evicted)
alongside the stored request/response cache, a single reusable
TableRowSorteris kept instead of rebuilt per run, and cell-renderer fonts are cached instead of allocated on every repaint.
- Per-method filter. A row of method checkboxes
(
GET/POST/PUT/PATCH/DELETE) in the options panel. Only the checked methods are tested — for example, uncheckGETto skip all read-only requests. The choice persists for the session, so you no longer have to enable/disable the whole extension per request (a common pain point vs. Autorize).
v4.2 is a correctness, accuracy, and performance release. The headline change is that the verdict engine no longer flags "two identical responses" blindly — it now understands what those responses actually are.
- Authorization-aware verdict. Two identical responses are flagged as
SAME — Possible BAC/IDORonly when both are2xxsuccesses with a non-trivial body (mutating methods excepted). Two identical401/403/404/ error pages are now correctly reported asDenied (OK)— a properly secured endpoint, not a finding. - No-auth control request. For every endpoint a single unauthenticated
control request is sent. If the unauthenticated response matches the
authenticated one, the endpoint is simply public and the pair is
suppressed as
Public endpoint (no-auth OK)instead of being reported. - Network errors are isolated. A failed request is marked
ERRORand excluded from the verdict, so two failures never collapse into a falseSAME.
- Structural JSON comparison. Bodies are compared by normalizing JSON
(volatile keys such as
csrf,nonce,timestamp,requestId,tokendropped; keys sorted) and, for non-JSON, by a similarity ratio — instead of an exact MD5 of the raw body. Dynamic responses that used to be missed now match.
- Concurrent requests. All per-endpoint requests (every user + the no-auth control) are sent in parallel through a bounded pool instead of sequentially.
- Smooth UI. The Activity Log batches updates and trims through the document
model — no more full
getText/split/setTextper line. This fixes the stutter / "buttons load one by one" when switching Burp tabs during long sessions. - Bounded memory. Stored request/response entries are capped (oldest evicted) and the Proof-of-Concept message editors are reused across label changes instead of being rebuilt, preventing heap growth over long sessions.
| Result | Meaning | Action |
|---|---|---|
SAME — Possible BAC/IDOR |
Both identities got the same successful (2xx) resource → likely broken access control | Investigate |
MIXED |
Some user pairs are SAME, others differ | Investigate the SAME pairs |
Different (OK) |
Responses differ across identities | Secure |
Denied (OK) |
Identical non-2xx responses (e.g. both 403) |
Secure — correctly denied |
Public endpoint (no-auth OK) |
Response matches the unauthenticated control | Not access-controlled; not a finding |
ERROR — request failed |
A request could not be completed | Re-run / check connectivity |
- Multi-user authentication profiles (up to 12 users)
- Full per-user header table (Key: Value) — cookies are just a
Cookieheader row - Multiple headers per user (e.g.
Authorization+X-User-ID+Cookie) - Baseline (owner/attacker) designation
- Comparison modes: All vs Baseline and All vs All (matrix)
- Authorization-aware verdict engine with no-auth control
- Structural JSON / similarity comparison with custom Ignore-Regex
- Smart Filter (skips static assets, scores IDOR patterns)
- Per-method filter (test only the HTTP methods you select)
- Risk classification (HIGH / MEDIUM / LOW)
- Dynamic result columns that scale with user count
- Per-user color-coded, side-by-side Proof-of-Concept viewer
- Profile Import / Export (JSON) and CSV result export
- Concurrent request engine, capped memory, batched logging
- Broken Access Control (BAC)
- Insecure Direct Object References (IDOR)
- Horizontal & vertical privilege escalation
- Missing authorization checks
- Improper ownership validation
- Authorization bypass
- REST / JSON APIs
- GraphQL APIs
- SPAs
- Mobile APIs
- Extender → Options → Python Environment → select
jython-standalone-*.jar. - Extender → Extensions → Add → Type:
Python→ selectTokenTwin_Checker.py.
Requirements: Burp Suite Professional, Jython 2.7.
- Open the TokenTwin tab and add your authenticated user profiles
(fill each user's
Authorization/Cookieheaders). - Mark one user as Baseline (the owner), pick a comparison mode, and use
the Methods checkboxes to choose which HTTP methods to test (e.g. uncheck
GETto focus on state-changing requests). - In Burp, right-click one or more interesting requests → Send to TokenTwin Checker.
- Click ▶ Run Test.
- Review the
Resultstable; click a row to inspect the per-user Request/Response side by side. Use theSAME only/MIXED onlyfilters to focus on findings, and Export CSV to save.
Note on the no-auth control: for each endpoint TokenTwin also sends one unauthenticated copy of the request (used to detect public endpoints). For mutating methods (
POST/PUT/DELETE) this is an additional request to the target — normally rejected without effect, but be aware of it when testing destructive endpoints.
Use only against systems you are explicitly authorized to test.
