HTTP Parameter Pollution
HTTP Parameter Pollution (HPP) exploits how web servers and application frameworks handle duplicate query parameters in a single request. When the same parameter name appears more than once, each technology resolves the conflict differently: some take the first value, some take the last, others concatenate all values or return them as an array. An attacker leverages this inconsistency to bypass input validation, override security filters, or inject unexpected values into application logic. HPP applies to query strings, POST bodies, cookies, and any context where parameters are parsed from a formatted string. HPP is especially useful for WAF bypass when combined with XSS filter bypass techniques: splitting an XSS payload across duplicate parameters evades signature-based detection.
Server Behavior
The way a server resolves duplicate parameters determines which HPP techniques apply to a given target. The table below shows the default behavior for common web technologies when receiving ?id=1&id=2.
The critical scenario arises when a front-end component (proxy, WAF, or validation layer) parses parameters differently than the backend application. A WAF inspecting the first value while the backend uses the last creates a bypass window the attacker walks through.
Server-Side HPP
Server-side HPP targets backend logic that processes parameters without accounting for duplicates. When an application builds internal requests, API calls, or database queries using user-supplied parameters, injecting a duplicate can override the intended value or introduce parameters the application did not expect.
If a validation layer checks the first occurrence of a parameter but the backend uses the last, the attacker passes validation with a benign value and delivers the real payload as a second occurrence.
{"status":"success","transferred":10000}
The validation layer reads amount=1 (first occurrence) and approves the request. The PHP backend calls $_POST['amount'], which returns the last value, processing a transfer of 10000.
For Tomcat/Java targets where the first value wins, reverse the order: place the payload first and the clean value second so the WAF checks the benign trailing value.
HPP also targets applications that pass user input into server-side HTTP requests. If the backend appends a user-supplied value to an internal URL without encoding it, a URL-encoded ampersand (%26) injects additional parameters into the internal request.
{"user":"guest","admin":true,"data":"restricted_content"}
The server decodes %26 to & before constructing the internal request, turning it into http://internal-api/data&admin=true. The internal service treats admin=true as a legitimate parameter.
Client-Side HPP
Client-side HPP targets URLs that the application constructs in the browser using values from the current request. When an application reflects a parameter into a link, form action, or iframe source without sanitizing it, the attacker injects additional parameters that alter the destination URL behavior.
A common target is OAuth callback URLs or share links where the application appends a user-controlled parameter to a base URL. If the application does not encode the value before inserting it, an injected & introduces new parameters.
< HTTP/1.1 302 Found < Location: https://legit.com/cb&scope=admin&code=abc123
Explain command
| -v | Shows response headers including the Location redirect header. |
The application builds the redirect URL by appending the authorization code. The injected scope=admin reaches the callback endpoint as a separate parameter, potentially escalating the granted permissions.
Another vector is form actions or links built from URL parameters. If a page reflects a parameter value into an href or form action, HPP overrides existing parameters when the user clicks.
<a href="/vote?link=vote&candidate=attacker&token=xyz">Submit</a>
The %26 decodes to & inside the href, adding candidate=attacker as a separate parameter. When the victim clicks the link, the backend processes the injected value. This is especially effective when the injected parameter overrides a value set by the application (like a hidden form field).
WAF Bypass via HPP
Web Application Firewalls typically inspect each parameter value individually. When the backend concatenates or joins duplicate parameter values before processing them, splitting an injection payload across multiple occurrences of the same parameter evades signature-based detection.
On IIS/ASP.NET, duplicate parameters are joined with a comma. A SQL injection payload split across two values reassembles into a valid query on the backend. Using SQL comments (/* */) to wrap the comma keeps the query syntactically correct.
admin:5f4dcc3b5aa765d61d8327deb882cf99 user1:e99a18c428cb38d5f260853678922e03
The WAF sees two separate values: 1 UNION SELECT/* and */username,password FROM users--. Neither matches a full SQL injection signature. ASP.NET joins them with a comma into 1 UNION SELECT/*,*/username,password FROM users--. The SQL comment /* ... */ wraps the comma, producing a valid UNION query.
The same approach applies to XSS payloads. Split the payload so each fragment looks benign to the WAF, and use a JavaScript comment to bridge the join character.
After comma-join the result is <script>alert(/*,*/document.cookie)</script>. The comma sits inside a JavaScript comment and is ignored, so the payload executes.
Notice
HPP-based WAF bypass only works when the backend joins duplicate parameter values. Test the target behavior with a benign duplicate parameter before crafting split payloads.
a = foo,bar
A comma-joined response confirms IIS/ASP.NET or similar behavior, making HPP payload splitting viable. If the response shows only one value, the backend takes first or last, which means the WAF bypass approach does not apply but server-side HPP (parameter override) still works.
HPP in REST APIs
REST APIs that accept query parameters or form data are vulnerable to HPP when they pass parameter values to internal logic without type checking. On frameworks that return arrays for duplicate parameters (Node.js/Express, PHP with bracket notation), repeated parameters bypass type validation or inject unexpected structures.
On Node.js/Express, duplicate parameters create an array. If the backend expects a string and performs string operations (regex matching, length checks, comparisons), receiving an array bypasses those checks or causes unexpected behavior.
{"users":[{"id":1,"name":"admin","role":"admin"},{"id":5,"name":"superuser","role":"admin"}]}
The application receives role as ["user", "admin"]. If the authorization check only validates the first element or uses an includes() check against the array, the admin value passes through to the database query.
PHP applications using bracket notation (param[]) accept array input through query strings and POST data. This bypasses string-based validation and can lead to mass operations on unintended records.
{"deleted":3,"message":"Records removed"}
The endpoint expects a single ID but receives an array. If the backend iterates over the array without authorization checks per item, the attacker deletes records they should not have access to.
JSON Duplicate Key Injection
Some JSON parsers accept duplicate keys in a request body, with the last value winning. This enables overriding fields that the application sets server-side or that appear earlier in the body.
{"id":42,"name":"attacker","role":"admin"}
Explain command
| -H "Content-Type: application/json" | Sends the body as JSON so the server parses it with its JSON decoder. |
The parser reads the first role as user, then overwrites it with admin from the duplicate key. RFC 8259 states that object member names should be unique but does not mandate rejection of duplicates. Most parsers silently accept them and use the last value.
References
-
OWASP: Testing for HTTP Parameter PollutionLINK: OWASP: Testing for HTTP Parameter Pollution, owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/04-Testing_for_HTTP_Parameter_Pollution (opens in new tab)
Testing methodology and server behavior reference for HPP.
-
PayloadsAllTheThings: HTTP Parameter PollutionREPO: PayloadsAllTheThings: HTTP Parameter Pollution, github.com/swisskyrepo/PayloadsAllTheThings/blob/master/HTTP%20Parameter%20Pollution/README.md (opens in new tab)
Payload collection and server behavior matrix for HPP.