Browse CTFs New CTF Sign in

Parameter pollution IDOR

web_auth_sessions Difficulty 1–5 30 min certifiable

Theory

Why This Matters

HTTP Parameter Pollution (HPP) was formally documented by Stefano Di Paola and Luca Carettoni at OWASP AppSec Europe 2009. They demonstrated that inconsistent handling of duplicate HTTP parameters across web servers, frameworks, and WAFs created an exploitable gap: a WAF might inspect the first occurrence of a parameter and pass the request as clean, while the backend application used the last occurrence — which carried the attacker's payload. Real-world exploitation of HPP has bypassed WAF-protected IDOR defences, circumvented signature-based injection filters, and manipulated server-side logic that aggregates duplicate parameters into arrays. OWASP lists HPP under Injection (A03:2021) and Security Misconfiguration (A05:2021). Its most significant real-world impact is enabling access-control bypass when a WAF or middleware inspects a different parameter occurrence than the application processes.

Core Concept

HTTP Parameter Pollution occurs when an HTTP request contains multiple parameters with the same name. The HTTP/1.1 specification does not define canonical handling for duplicate parameters, so each server and framework implements its own behaviour. This inconsistency creates a parsing differential that attackers can exploit.

Documented per-technology behaviours for duplicate parameters ?user_id=ATTACKER&user_id=VICTIM:

  • PHP / Apache: Last value wins → user_id = VICTIM
  • ASP.NET / IIS: First value wins → user_id = ATTACKER
  • Node.js (Express / qs library): All values merged into array → user_id = ['ATTACKER', 'VICTIM']
  • Java Servlet (Tomcat): getParameter() returns first; getParameterValues() returns all
  • Ruby on Rails: Last value wins for scalar params; merged into array for bracket notation
  • Python (Django / Flask): request.GET['user_id'] returns last; request.GET.getlist() returns all

The IDOR exploitation pattern exploits this inconsistency when a WAF or input-validation layer is positioned in front of the application. The WAF inspects one occurrence (often the first) of user_id and validates it belongs to the authenticated user. The backend application uses a different occurrence — the attacker's injected value — to execute the database query, bypassing the access-control check entirely.

An additional exploitation path involves parameter array injection: frameworks that merge duplicates into arrays may pass the array to a SQL query builder or ORM in unexpected ways, either causing an error that reveals schema information or querying with a different effective value than intended.

Technical Deep-Dive

-- Scenario: WAF validates first user_id (101 = attacker own ID), passes request
-- Backend PHP application uses last user_id (200 = victim ID)
-- Result: WAF bypass + IDOR

GET /api/profile?user_id=101&user_id=200 HTTP/1.1
Host: victim.com
Cookie: session=<attacker_session>

-- PHP backend (last wins) returns victim data:
HTTP/1.1 200 OK
Content-Type: application/json

{"user_id":200,"name":"Victim User","email":"[email protected]","ssn":"XXX-XX-1234"}
-- HPP in POST body (application/x-www-form-urlencoded)
POST /api/transfer HTTP/1.1
Host: bank.victim.com
Content-Type: application/x-www-form-urlencoded
Cookie: session=<attacker_session>

amount=1&to_account=ATTACKER_ACCT&to_account=VICTIM_ACCT

-- ASP.NET (first wins): transfers to ATTACKER_ACCT
-- PHP (last wins):      transfers to VICTIM_ACCT
-- Node/qs (array):      may cause type error leaking debug info
# Automated HPP IDOR probe — test both orderings
import requests

session = "<attacker_session>"
my_id = 101
victim_id = 200

for params in [
    f"user_id={my_id}&user_id={victim_id}",    # attacker first
    f"user_id={victim_id}&user_id={my_id}",    # victim first
]:
    r = requests.get(
        f"https://victim.com/api/profile?{params}",
        cookies={"session": session},
        allow_redirects=False
    )
    data = r.json() if "application/json" in r.headers.get("content-type","") else {}
    if data.get("user_id") == victim_id:
        print(f"HPP IDOR confirmed with ordering: {params}")
        print(data)

Security Assessment Methodology

  1. Identify the server stack — Use Server, X-Powered-By, and X-AspNet-Version response headers, error page fingerprints, and cookie name patterns to determine the backend technology. This informs which duplicate-parameter behaviour to expect.
  2. Identify all user-scoped parameters — Look for user_id, account_id, uid, id, and owner in URL query strings, POST bodies, and JSON payloads.
  3. Inject duplicates in both orderings — For each identified parameter, send the request with param=OWN_VALUE&param=VICTIM_VALUE and then the reverse ordering. Observe which value the application processes.
  4. Test POST bodies — Replicate the same dual-parameter technique in application/x-www-form-urlencoded bodies; note that JSON bodies do not support duplicate keys in standard form, though some parsers tolerate them.
  5. Test WAF bypass specifically — If a WAF appears to be blocking direct IDOR attempts (403 on ?user_id=VICTIM), HPP is a candidate bypass; the WAF may validate the first parameter while the backend uses the last.
  6. Use Burp Suite Param Miner to detect hidden duplicate parameter handling and Burp Repeater to manually craft dual-parameter requests.
  7. Test array injection side effects — For Node.js targets, try ?user_id[]=101&user_id[]=200 (bracket notation) to force array coercion and observe error messages or unexpected data.

Defensive Countermeasure — Configure the application to reject requests containing duplicate parameter names at the input validation layer, before any business logic executes. If the WAF and application server are different products, ensure they use identical parameter parsing semantics, or configure the WAF to block any request with duplicate parameter names. Enforce parameter uniqueness in schema validation (e.g., JSON Schema additionalProperties: false combined with strict body parsers).

Common Assessment Errors

  • Assuming JSON bodies are immune — While JSON does not formally support duplicate keys, some parsers (including Node.js JSON.parse) return the last duplicate key's value; others throw errors. Test JSON bodies for duplicate key handling.
  • Not testing both orderings — Whether first or last wins depends on the backend technology; always test attacker-first and victim-first orderings separately.
  • Missing the WAF bypass angle — HPP's primary real-world value is bypassing security controls positioned in front of the application; do not evaluate HPP only as a standalone IDOR but as an evasion primitive.
  • Forgetting URL-encoded ampersands inside valuesuser_id=101%26user_id%3D200 (double-encoded) may bypass WAF parameter splitting while the backend's URL decoder produces the duplicate; test encoded variants.
  • Not checking array coercion effects — On frameworks that merge duplicates into arrays, the array may be passed to an ORM that serialises it to SQL in unexpected ways (e.g., WHERE user_id IN (101, 200)) — returning both users' data.
  • Treating 400 Bad Request as definitive rejection — Some applications return 400 on malformed input but still process one of the parameter values before issuing the error; check whether side effects occurred.

NICE Framework Alignment

Code Knowledge/Skill/Task Statement How This Card Develops It
K0007 Knowledge of authentication, authorization, and access control methods Explains how HPP bypasses WAF-based access control by exploiting parameter parsing differentials between security and application layers
K0065 Knowledge of policy-based access control Covers the need for consistent parameter semantics between WAF and application to enforce a coherent access policy
K0070 Knowledge of common application vulnerabilities Deep-dives HPP as an injection and evasion technique with per-framework parsing behaviour documented
S0001 Skill in conducting vulnerability scans and recognizing vulnerabilities in security systems Practises dual-ordering HPP injection with Burp Repeater and Param Miner across URL and body parameters
T0028 Task: Identify systemic security issues based on vulnerability and configuration data Develops ability to recognise WAF/backend parsing differentials as a systemic access-control evasion risk

Further Reading

  • HTTP Parameter Pollution — Di Paola & Carettoni, OWASP AppSec Europe 2009 (whitepaper)
  • Web Application Hacker's Handbook, 2nd ed. — Stuttard & Pinto, Wiley
  • OWASP Testing Guide v4.2 — OTG-INPVAL-004: Testing for HTTP Parameter Pollution — OWASP Foundation
  • Hacking APIs: Breaking Web Application Programming Interfaces — Corey Ball, No Starch Press (2022)

Challenge Lab

Reinforce your learning with a hands-on generated challenge based on this card's competency.