Special HTTP headers
Wordlists & Tools
- https://github.com/danielmiessler/SecLists/tree/master/Miscellaneous/Web/http-request-headers
- https://github.com/rfc-st/humble
Headers that influence source or routing
Rewrite IP source:
X-Originating-IP: 127.0.0.1X-Forwarded-For: 127.0.0.1X-Forwarded: 127.0.0.1Forwarded-For: 127.0.0.1X-Forwarded-Host: 127.0.0.1X-Remote-IP: 127.0.0.1X-Remote-Addr: 127.0.0.1X-ProxyUser-Ip: 127.0.0.1X-Original-URL: 127.0.0.1Client-IP: 127.0.0.1X-Client-IP: 127.0.0.1X-Host: 127.0.0.1True-Client-IP: 127.0.0.1Cluster-Client-IP: 127.0.0.1Via: 1.0 fred, 1.1 127.0.0.1Connection: close, X-Forwarded-For(Check hop-by-hop headers)
Rewrite location:
X-Original-URL: /admin/consoleX-Rewrite-URL: /admin/console
Hop-by-Hop headers
A hop-by-hop header is a header which is designed to be processed and consumed by the proxy currently handling the request, as opposed to an end-to-end header.
Connection: close, X-Forwarded-For
HTTP Request Smuggling
Content-Length: 30Transfer-Encoding: chunked
The Expect header
An HTTP/1.1 client can send Expect: 100-continue; the server may answer with HTTP/1.1 100 Continue before the client sends the request body. Differences in how frontends and backends handle the expectation and body can expose desynchronization bugs.[8][10]
Interesting observed results of Expect: 100-continue testing include:[10]
- A
HEADrequest with a body can make an implementation wait for bytes or time out when its message-framing assumptions differ from the peer’s. - Some server chains have returned unexpected socket data, leaked secrets, or failed to strip a header consistently.
- A backend that returns an error before consuming a body while the frontend still forwards it can create a
0.CL/CL.0-style desynchronization: the leftover body is interpreted as the next request. - Obfuscated values such as
Expect: y 100-continuecan exercise a different frontend/backend parsing path. - Once request and response queues are out of sync, a response intended for one user can be assigned to another request. Validate suspected behavior with harmless canary requests rather than real victim traffic.
For more info about HTTP Request Smuggling check:
Cache Headers
Server Cache Headers:
X-Cachein the response may have the valuemisswhen the request wasn’t cached and the valuehitwhen it is cached- Similar behaviour in the header
Cf-Cache-Status
- Similar behaviour in the header
Cache-Controlindicates if a resource is being cached and when will be the next time the resource will be cached again:Cache-Control: public, max-age=1800Varyis often used in the response to indicate additional headers that are treated as part of the cache key even if they are normally unkeyed.Agedefines the times in seconds the object has been in the proxy cache.Server-Timing: cdn-cache; desc=HITalso indicates that a resource was cached
Browser and legacy cache headers:[9]
Clear-Site-Data: Header to indicate the cache that should be removed:Clear-Site-Data: "cache", "cookies"Expires: Contains date/time when the response should expire:Expires: Wed, 21 Oct 2015 07:28:00 GMTPragma: no-cacheis a deprecated HTTP/1.0 request directive retained for compatibility; its response semantics were never a reliable substitute forCache-Control: no-cache.Warninghistorically carried cache/status warnings such asWarning: 110 anderson/1.3.37 "Response is stale", but RFC 9111 obsoletes the field.[9]
Conditionals
Last-Modifiedis a response validator containing the origin server’s selected modification time for the representation. Clients can send that value inIf-Modified-SinceorIf-Unmodified-Since; coarse or synthetic timestamps and clock behavior can affect its reliability.[8]If-Modified-Sinceasks for the representation only if it changed after the supplied date; otherwise a successful conditionalGET/HEADnormally receives304.If-Unmodified-Sinceinstead requires that the resource has not changed and otherwise normally produces412for a state-changing request.[8]If-Matchrequires a current entity-tag match, whileIf-None-Matchrequires no match. ForGET/HEAD, a failedIf-None-Matchcondition normally returns304; for other methods it returns412.[8]- Entity-tag generation is implementation-specific. For example,
W/"37-eL2g8DEyqntYlaLp5XLInBWsjWI"is a weak validator from a particular framework; its syntax alone does not prove that the value is SHA-1 or that37represents a byte count.
- Entity-tag generation is implementation-specific. For example,
Range requests
Accept-Ranges: Indicates if the server supports range requests, and if so in which unit the range can be expressed.Accept-Ranges: <range-unit>Range: Requests part of a representation. For example,Range: bytes=80-100asks for bytes 80 through 100 and can produce206 Partial Content. RemovingAccept-Encodingoften makes byte offsets easier to reason about.[8]- If an attacker can inject a
Rangerequest header, a partial response may isolate reflected JavaScript or other bytes that were harmless in the complete representation. Exploitability depends on browser behavior, content type, and intermediary caching.
- If an attacker can inject a
If-Range: Creates a conditional range request that is only fulfilled if the given etag or date matches the remote resource. Used to prevent downloading two ranges from incompatible version of the resource.Content-Range: Indicates where in a full body message a partial message belongs.
Message body information
Content-Length: The size of the resource, in decimal number of bytes.Content-Type: Indicates the media type of the resourceContent-Encoding: Used to specify the compression algorithm.Content-Language: Describes the human language(s) intended for the audience, so that it allows a user to differentiate according to the users’ own preferred language.Content-Location: Indicates an alternate location for the returned data.
These fields are often routine, but differences on a resource protected by 401 or 403 can become an oracle for hidden content.
For example a combination of Range and Etag in a HEAD request can leak the content of the page via HEAD requests:
- A request with the header
Range: bytes=20-20and with a response containingETag: W/"1-eoGvPlkaxxP4HqHv6T3PNhV9g3Y"is leaking that the SHA1 of the byte 20 isETag: eoGvPlkaxxP4HqHv6T3PNhV9g3Y
Request-body Content-Encoding abuse
If the server accepts request bodies with a Content-Encoding header, test whether unsupported encodings are rejected before the body reaches any decompressor/parser. A common bug class is tying the rejection logic to an unrelated feature flag (for example, “HTTP compression enabled”). If that gate is wrong, an attacker may be able to reach a code path developers believed was unreachable.[6]
Generic checks:
- Send a POST with a non-empty body and vary
Content-Encodingacrossgzip,deflate,br,compress, andidentity. - Compare behavior when the same endpoint receives the same body without
Content-Encoding. - Look for crashes, connection resets, allocator aborts,
500responses, or inconsistent4xx/5xxhandling. - Repeat through the real origin and through any reverse proxy/WAF, because proxies may strip the header, synthesize their own
415, or hide the backendServerheader.
Example probe:
POST / HTTP/1.1
Host: target
Content-Encoding: deflate
Content-Length: 4
AAAA
If the target should not support compressed request bodies, the safest behavior is an early 415 Unsupported Media Type (or similar explicit rejection) before any decompression attempt.
Safe patch-oracle detection with Content-Encoding: identity
When the dangerous value is known to crash the service, look for a patch behavior oracle instead of replaying the destructive request. A useful pattern is to send a benign body with Content-Encoding: identity:
POST / HTTP/1.1
Host: target
Content-Encoding: identity
Content-Length: 10
AAAAAAAAAA
Why this is useful:
- A patched target may reject any request that has both a body and a non-empty
Content-Encodingheader, often with415 Unsupported Media Type. - A vulnerable target may still process the
identityrequest normally and return app-specific codes such as200,302,401, or404. - If the response still fingerprints the product (for example via
Server), you can often turn this into a production-safe vulnerable/patched detector without ever sending the crashing encoding.
This pattern was useful in SolarWinds Serv-U (<= 15.5.4.108), where POST + body + Content-Encoding: deflate reached an unsafe in-memory deflate decompressor and reliably crashed the process, while the hotfix added a generic 415 gate for requests carrying a body plus any non-empty Content-Encoding header.[6][7]
Server Info
Server: Apache/2.4.1 (Unix)X-Powered-By: PHP/5.3.3
Controls
Allow: This header is used to communicate the HTTP methods a resource can handle. For example, it might be specified asAllow: GET, POST, HEAD, indicating that the resource supports these methods.Expect: Utilized by the client to convey expectations that the server needs to meet for the request to be processed successfully. A common use case involves theExpect: 100-continueheader, which signals that the client intends to send a large data payload. The client looks for a100 (Continue)response before proceeding with the transmission. This mechanism helps in optimizing network usage by awaiting server confirmation.
Downloads
- The
Content-Dispositionheader in HTTP responses directs whether a file should be displayed inline (within the webpage) or treated as an attachment (downloaded). For instance:
Content-Disposition: attachment; filename="filename.jpg"
This means the file named “filename.jpg” is intended to be downloaded and saved.[2]
Security Headers
Content Security Policy (CSP)
Content Security Policy Csp Bypass
Trusted Types
By enforcing Trusted Types through CSP, applications can be protected against DOM XSS attacks. Trusted Types ensure that only specifically crafted objects, compliant with established security policies, can be used in dangerous web API calls, thereby securing JavaScript code by default.
// Feature detection
if (window.trustedTypes && trustedTypes.createPolicy) {
// Name and create a policy
const policy = trustedTypes.createPolicy('escapePolicy', {
createHTML: str => str.replace(/\</g, '<').replace(/>/g, '>');
});
}
// Assignment of raw strings is blocked, ensuring safety.
el.innerHTML = "some string" // Throws an exception.
const escaped = policy.createHTML("<img src=x onerror=alert(1)>")
el.innerHTML = escaped // Results in safe assignment.
X-Content-Type-Options
This header prevents MIME type sniffing, a practice that could lead to XSS vulnerabilities. It ensures that browsers respect the MIME types specified by the server.[3]
X-Content-Type-Options: nosniff
X-Frame-Options
To combat clickjacking, this header restricts how documents can be embedded in <frame>, <iframe>, <embed>, or <object> tags, recommending all documents to specify their embedding permissions explicitly.[3]
X-Frame-Options: DENY
Cross-Origin Resource Policy (CORP) and Cross-Origin Resource Sharing (CORS)
CORP is crucial for specifying which resources can be loaded by websites, mitigating cross-site leaks. CORS, on the other hand, allows for a more flexible cross-origin resource sharing mechanism, relaxing the same-origin policy under certain conditions.[3]
Cross-Origin-Resource-Policy: same-origin
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true
Cross-Origin Embedder Policy (COEP) and Cross-Origin Opener Policy (COOP)
COEP and COOP are essential for enabling cross-origin isolation, significantly reducing the risk of Spectre-like attacks. They control the loading of cross-origin resources and the interaction with cross-origin windows, respectively.[3]
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin-allow-popups
HTTP Strict Transport Security (HSTS)
Lastly, HSTS is a security feature that forces browsers to communicate with servers only over secure HTTPS connections, thereby enhancing privacy and security.[3]
Strict-Transport-Security: max-age=3153600
Permissions-Policy (formerly Feature-Policy)
Permissions-Policy allows web developers to selectively enable, disable, or modify the behaviour of certain browser features and APIs within a document. It is the successor to the now-deprecated Feature-Policy header. This header helps reduce the attack surface by restricting access to powerful features that could be abused.[4][5]
Permissions-Policy: geolocation=(), camera=(), microphone=()
Common directives:
| Directive | Description |
|---|---|
accelerometer | Controls access to the Accelerometer sensor |
camera | Controls access to video input devices (webcam) |
geolocation | Controls access to the Geolocation API |
gyroscope | Controls access to the Gyroscope sensor |
magnetometer | Controls access to the Magnetometer sensor |
microphone | Controls access to audio input devices |
payment | Controls access to the Payment Request API |
usb | Controls access to the WebUSB API |
fullscreen | Controls access to the Fullscreen API |
autoplay | Controls whether media can autoplay |
clipboard-read | Controls access to read clipboard content |
clipboard-write | Controls access to write to the clipboard |
Syntax values:
()- Disables the feature entirely(self)- Allows the feature only for the same origin*- Allows the feature for all origins(self "https://example.com")- Allows for same origin and specified domain
Example configurations:
# Restrictive policy - disable most features
Permissions-Policy: geolocation=(), camera=(), microphone=(), payment=(), usb=()
# Allow camera only from same origin
Permissions-Policy: camera=(self)
# Allow geolocation for same origin and a trusted partner
Permissions-Policy: geolocation=(self "https://maps.example.com")
From a security perspective, missing or overly permissive Permissions-Policy headers may allow attackers (e.g., through XSS or embedded iframes) to abuse powerful browser features. Always restrict features to the minimum necessary for your application.
Header Name Casing Bypass
HTTP field names are case-insensitive (RFC 9110 §5.1). Nevertheless, custom middleware, security filters, or business logic sometimes compare the literal header name without normalizing its case. If a filter is case-sensitive but the downstream consumer is compliant and case-insensitive, an attacker may bypass the filter with different capitalization.[1][8]
Typical situations where this mistake appears:
- Custom allow/deny lists that try to block “dangerous” internal headers before the request reaches a sensitive component.
- In-house implementations of reverse-proxy pseudo-headers (e.g.
X-Forwarded-Forsanitisation). - Frameworks that expose management / debug endpoints and rely on header names for authentication or command selection.
Abusing the bypass
- Identify a header that is filtered or validated server-side (for example, by reading source code, documentation, or error messages).
- Send the same header with different casing. Whether the spelling survives to vulnerable user code depends on the server and framework, so test the complete proxy-to-application chain.
- If the downstream component treats headers in a case-insensitive way (most do), it will accept the attacker-controlled value.
Example: Apache Camel exec RCE (CVE-2025-27636)
In vulnerable versions of Apache Camel the Command Center routes try to block untrusted requests by stripping the headers CamelExecCommandExecutable and CamelExecCommandArgs. The comparison was done with equals() so only the exact lowercase names were removed.
# Bypass the filter by using mixed-case header names and execute `ls /` on the host
curl "http://<IP>/command-center" \
-H "CAmelExecCommandExecutable: ls" \
-H "CAmelExecCommandArgs: /"
The headers reach the exec component unfiltered, resulting in remote command execution with the privileges of the Camel process.
Detection & Mitigation
- Normalise all header names to a single case (usually lowercase) before performing allow/deny comparisons.
- Reject suspicious duplicates: if both
Header:andHeAdEr:are present, treat it as an anomaly. - Use a positive allow-list enforced after canonicalisation.
- Protect management endpoints with authentication and network segmentation.
References
- [1] CVE-2025-27636 – RCE in Apache Camel via header casing bypass (OffSec blog)
- [2] MDN Web Docs - Content-Disposition
- [3] MDN Web Docs - HTTP headers reference
- [4] web.dev - Security headers quick reference
- [5] web.dev - Security headers article
- [6] Bishop Fox - A Crash, Not a Shell: SolarWinds Serv-U CVE-2026-28318
- [7] BishopFox/CVE-2026-28318-check
- [8] RFC 9110: HTTP Semantics
- [9] RFC 9111: HTTP Caching
- [10] PortSwigger Research: HTTP/1.1 must die — the desync endgame