Description
HTTP Parameter Pollution (HPP) exploits the fact that the HTTP specification does not define how servers should handle duplicate query string or POST body parameters. Different frameworks, languages, and servers handle this ambiguity in entirely different ways: some take the first value, some take the last value, some concatenate all values with a comma, and some treat the parameter as an array. When a web application and its upstream WAF, reverse proxy, or partner API parse the same request differently, an attacker can craft requests that appear benign to the security layer but deliver a malicious value to the application.
HPP falls under CWE-88 (Argument Injection) and OWASP A03:2021 (Injection) because the attacker is manipulating the argument structure of an HTTP request to inject unintended values. The vulnerability class is particularly relevant in architectures with multiple processing layers — API gateways fronting backend services, WAFs protecting application servers, or frontend services that forward parameters to internal APIs.
HPP is also effective as a logic manipulation technique within a single application: duplicating parameters that represent authorization tokens, user IDs, or transfer amounts can override intended values when the application processes parameters in an unexpected order.
How It Works
WAF bypass example. A WAF blocks requests containing <script> in any parameter:
GET /search?q=<script>alert(1)</script>
→ Blocked by WAF
With HPP, the attacker sends:
GET /search?q=legitimate&q=<script>alert(1)</script>
If the WAF evaluates only the first q value (legitimate) but the application uses the last value (<script>alert(1)</script>), the payload bypasses the WAF and reaches the application.
Authorization bypass example. A funds transfer endpoint uses a to_account parameter. The application processes the last occurrence, but audit logging records the first:
POST /transfer
amount=1000&to_account=ATTACKER_ACCOUNT&to_account=VICTIM_ACCOUNT
The audit log shows the transfer going to the victim's account, while the application actually sends funds to the attacker's account — a parameter override attack.
Server-side HPP in API forwarding. When a frontend service appends parameters to a backend API call:
# Frontend constructs: /api/backend?role=user&USER_SUPPLIED_PARAMS
# Attacker injects: ?role=admin
# Final backend URL: /api/backend?role=user&role=admin
If the backend takes the last role value, the attacker elevates their privilege.
Parameter parsing behavior by platform: PHP ($_GET) takes the last value; ASP.NET takes the first; Node.js/Express with qs creates an array; Flask/Python takes the first; JSP takes all values as an array.
Impact
- WAF and Security Control Bypass — Smuggling malicious payloads past security filters by exploiting different parameter parsing behavior between the WAF and the application
- Authorization Logic Bypass — Overriding access control parameters (user IDs, role flags, account numbers) by exploiting which duplicate value the application uses
- Audit Log Manipulation — Creating discrepancies between what security logs record and what the application actually executed
- Business Logic Abuse — Manipulating transfer amounts, discount codes, and quantity fields by injecting duplicate parameters
Detection
- Duplicate every parameter in key requests — add a second copy of each parameter with a different value (e.g.,
id=1&id=2) and observe which value the application uses. Test with Burp Suite Repeater. - Test WAF bypass — submit a duplicate parameter where the first value is benign and the second contains a known WAF-blocked payload (e.g., SQL injection syntax). If the payload reaches the application, HPP bypasses the WAF.
- Map multi-tier architectures — identify all layers that parse HTTP parameters (WAF, API gateway, application) and test each boundary independently.
- Fuzz authorization parameters — duplicate
role,user_id,account,admin, andtokenparameters with escalated values. Verify whether the application enforces authorization based on the expected value. - Test with arrays — send
param[]=value1¶m[]=value2andparam=value1,value2. Some frameworks interpret these as arrays, which can bypass equality checks. - Review API forwarding code — look for functions that append user-supplied parameters to outbound API URLs or request bodies, which can introduce HPP into downstream services.
Remediation
Use consistent parameter parsing. Define and document which value should be used when duplicate parameters are received (first, last, or reject-if-duplicate) and enforce this uniformly across all layers.
Reject duplicate parameters. The safest approach is to return a 400 Bad Request if the same parameter name appears more than once in a request, eliminating any ambiguity:
// Express.js middleware — reject duplicate parameters
app.use((req, res, next) => {
const keys = Object.keys(req.query);
const rawQuery = req.url.split('?')[1] || '';
const rawKeys = rawQuery.split('&').map(p => p.split('=')[0]);
const hasDuplicates = rawKeys.length !== new Set(rawKeys).size;
if (hasDuplicates) return res.status(400).json({ error: 'Duplicate parameters' });
next();
});
Align WAF and application parsing. Configure the WAF to evaluate all occurrences of a parameter — not just the first or last — when applying security rules.
Validate security-sensitive parameters strictly. For parameters that control authorization (role, user_id, account), validate that exactly one value is present and that it matches the expected format before using it.
