special-http-headers.md (20000B)
1 --- 2 title: "Special HTTP headers" 3 section: "Network Services" 4 sectionSlug: "network-services-pentesting" 5 sourcePath: "src/network-services-pentesting/pentesting-web/special-http-headers.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-web/special-http-headers.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Special HTTP headers 14 15 ## Wordlists & Tools 16 17 - [https://github.com/danielmiessler/SecLists/tree/master/Miscellaneous/Web/http-request-headers](https://github.com/danielmiessler/SecLists/tree/master/Miscellaneous/Web/http-request-headers) 18 - [https://github.com/rfc-st/humble](https://github.com/rfc-st/humble) 19 20 ## Headers that influence source or routing 21 22 Rewrite **IP source**: 23 24 - `X-Originating-IP: 127.0.0.1` 25 - `X-Forwarded-For: 127.0.0.1` 26 - `X-Forwarded: 127.0.0.1` 27 - `Forwarded-For: 127.0.0.1` 28 - `X-Forwarded-Host: 127.0.0.1` 29 - `X-Remote-IP: 127.0.0.1` 30 - `X-Remote-Addr: 127.0.0.1` 31 - `X-ProxyUser-Ip: 127.0.0.1` 32 - `X-Original-URL: 127.0.0.1` 33 - `Client-IP: 127.0.0.1` 34 - `X-Client-IP: 127.0.0.1` 35 - `X-Host: 127.0.0.1` 36 - `True-Client-IP: 127.0.0.1` 37 - `Cluster-Client-IP: 127.0.0.1` 38 - `Via: 1.0 fred, 1.1 127.0.0.1` 39 - `Connection: close, X-Forwarded-For` (Check hop-by-hop headers) 40 41 Rewrite **location**: 42 43 - `X-Original-URL: /admin/console` 44 - `X-Rewrite-URL: /admin/console` 45 46 ## Hop-by-Hop headers 47 48 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. 49 50 - `Connection: close, X-Forwarded-For` 51 52 53 [Abusing Hop By Hop Headers](/hacktricks/pentesting-web/abusing-hop-by-hop-headers) 54 55 ## HTTP Request Smuggling 56 57 - `Content-Length: 30` 58 - `Transfer-Encoding: chunked` 59 60 61 [Http Request Smuggling](/hacktricks/pentesting-web/http-request-smuggling/overview) 62 63 ## The Expect header 64 65 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.<sup>[[8]](#references)[[10]](#references)</sup> 66 67 Interesting observed results of `Expect: 100-continue` testing include:<sup>[[10]](#references)</sup> 68 69 - A `HEAD` request with a body can make an implementation wait for bytes or time out when its message-framing assumptions differ from the peer's. 70 - Some server chains have returned unexpected socket data, leaked secrets, or failed to strip a header consistently. 71 - 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. 72 - Obfuscated values such as `Expect: y 100-continue` can exercise a different frontend/backend parsing path. 73 - 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. 74 75 For more info about HTTP Request Smuggling check: 76 77 [Http Request Smuggling](/hacktricks/pentesting-web/http-request-smuggling/overview) 78 79 80 ## Cache Headers 81 82 **Server Cache Headers**: 83 84 - **`X-Cache`** in the response may have the value **`miss`** when the request wasn't cached and the value **`hit`** when it is cached 85 - Similar behaviour in the header **`Cf-Cache-Status`** 86 - **`Cache-Control`** indicates if a resource is being cached and when will be the next time the resource will be cached again: `Cache-Control: public, max-age=1800` 87 - **`Vary`** is often used in the response to **indicate additional headers** that are treated as **part of the cache key** even if they are normally unkeyed. 88 - **`Age`** defines the times in seconds the object has been in the proxy cache. 89 - **`Server-Timing: cdn-cache; desc=HIT`** also indicates that a resource was cached 90 91 92 [Cache Deception](/hacktricks/pentesting-web/cache-deception/overview) 93 94 **Browser and legacy cache headers**:<sup>[[9]](#references)</sup> 95 96 - `Clear-Site-Data`: Header to indicate the cache that should be removed: `Clear-Site-Data: "cache", "cookies"` 97 - `Expires`: Contains date/time when the response should expire: `Expires: Wed, 21 Oct 2015 07:28:00 GMT` 98 - `Pragma: no-cache` is a deprecated HTTP/1.0 request directive retained for compatibility; its response semantics were never a reliable substitute for `Cache-Control: no-cache`. 99 - `Warning` historically carried cache/status warnings such as `Warning: 110 anderson/1.3.37 "Response is stale"`, but RFC 9111 obsoletes the field.<sup>[[9]](#references)</sup> 100 101 ## Conditionals 102 103 - **`Last-Modified`** is a response validator containing the origin server's selected modification time for the representation. Clients can send that value in `If-Modified-Since` or `If-Unmodified-Since`; coarse or synthetic timestamps and clock behavior can affect its reliability.<sup>[[8]](#references)</sup> 104 - **`If-Modified-Since`** asks for the representation only if it changed after the supplied date; otherwise a successful conditional `GET`/`HEAD` normally receives `304`. **`If-Unmodified-Since`** instead requires that the resource has not changed and otherwise normally produces `412` for a state-changing request.<sup>[[8]](#references)</sup> 105 - **`If-Match`** requires a current entity-tag match, while **`If-None-Match`** requires no match. For `GET`/`HEAD`, a failed `If-None-Match` condition normally returns `304`; for other methods it returns `412`.<sup>[[8]](#references)</sup> 106 - 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 that `37` represents a byte count. 107 108 ## Range requests 109 110 - **`Accept-Ranges`**: Indicates if the server supports range requests, and if so in which unit the range can be expressed. `Accept-Ranges: <range-unit>` 111 - **`Range`**: Requests part of a representation. For example, `Range: bytes=80-100` asks for bytes 80 through 100 and can produce `206 Partial Content`. Removing `Accept-Encoding` often makes byte offsets easier to reason about.<sup>[[8]](#references)</sup> 112 - If an attacker can inject a `Range` request 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. 113 - **`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. 114 - **`Content-Range`**: Indicates where in a full body message a partial message belongs. 115 116 ## Message body information 117 118 - **`Content-Length`:** The size of the resource, in decimal number of bytes. 119 - **`Content-Type`**: Indicates the media type of the resource 120 - **`Content-Encoding`**: Used to specify the compression algorithm. 121 - **`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. 122 - **`Content-Location`**: Indicates an alternate location for the returned data. 123 124 These fields are often routine, but differences on a resource protected by `401` or `403` can become an oracle for hidden content.\ 125 For example a combination of **`Range`** and **`Etag`** in a HEAD request can leak the content of the page via HEAD requests: 126 127 - A request with the header `Range: bytes=20-20` and with a response containing `ETag: W/"1-eoGvPlkaxxP4HqHv6T3PNhV9g3Y"` is leaking that the SHA1 of the byte 20 is `ETag: eoGvPlkaxxP4HqHv6T3PNhV9g3Y` 128 129 ### Request-body `Content-Encoding` abuse 130 131 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.<sup>[[6]](#references)</sup> 132 133 Generic checks: 134 135 - Send a **POST** with a **non-empty body** and vary `Content-Encoding` across `gzip`, `deflate`, `br`, `compress`, and `identity`. 136 - Compare behavior when the same endpoint receives the same body **without** `Content-Encoding`. 137 - Look for crashes, connection resets, allocator aborts, `500` responses, or inconsistent `4xx/5xx` handling. 138 - Repeat through the **real origin** and through any **reverse proxy/WAF**, because proxies may strip the header, synthesize their own `415`, or hide the backend `Server` header. 139 140 Example probe: 141 142 ```http 143 POST / HTTP/1.1 144 Host: target 145 Content-Encoding: deflate 146 Content-Length: 4 147 148 AAAA 149 ``` 150 151 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. 152 153 ### Safe patch-oracle detection with `Content-Encoding: identity` 154 155 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`: 156 157 ```http 158 POST / HTTP/1.1 159 Host: target 160 Content-Encoding: identity 161 Content-Length: 10 162 163 AAAAAAAAAA 164 ``` 165 166 Why this is useful: 167 168 - A **patched** target may reject **any** request that has both a body and a **non-empty** `Content-Encoding` header, often with **`415 Unsupported Media Type`**. 169 - A **vulnerable** target may still process the `identity` request normally and return app-specific codes such as `200`, `302`, `401`, or `404`. 170 - 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. 171 172 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.<sup>[[6]](#references)[[7]](#references)</sup> 173 174 ## Server Info 175 176 - `Server: Apache/2.4.1 (Unix)` 177 - `X-Powered-By: PHP/5.3.3` 178 179 ## Controls 180 181 - **`Allow`**: This header is used to communicate the HTTP methods a resource can handle. For example, it might be specified as `Allow: GET, POST, HEAD`, indicating that the resource supports these methods. 182 - **`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 the `Expect: 100-continue` header, which signals that the client intends to send a large data payload. The client looks for a `100 (Continue)` response before proceeding with the transmission. This mechanism helps in optimizing network usage by awaiting server confirmation. 183 184 ## Downloads 185 186 - The **`Content-Disposition`** header in HTTP responses directs whether a file should be displayed **inline** (within the webpage) or treated as an **attachment** (downloaded). For instance: 187 188 ```text 189 Content-Disposition: attachment; filename="filename.jpg" 190 ``` 191 192 This means the file named "filename.jpg" is intended to be downloaded and saved.<sup>[[2]](#references)</sup> 193 194 ## Security Headers 195 196 ### Content Security Policy (CSP) <a href="#csp" id="csp"></a> 197 198 199 [Content Security Policy Csp Bypass](/hacktricks/pentesting-web/content-security-policy-csp-bypass/overview) 200 201 ### **Trusted Types** 202 203 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. 204 205 ```javascript 206 // Feature detection 207 if (window.trustedTypes && trustedTypes.createPolicy) { 208 // Name and create a policy 209 const policy = trustedTypes.createPolicy('escapePolicy', { 210 createHTML: str => str.replace(/\</g, '<').replace(/>/g, '>'); 211 }); 212 } 213 ``` 214 215 ```javascript 216 // Assignment of raw strings is blocked, ensuring safety. 217 el.innerHTML = "some string" // Throws an exception. 218 const escaped = policy.createHTML("<img src=x onerror=alert(1)>") 219 el.innerHTML = escaped // Results in safe assignment. 220 ``` 221 222 ### **X-Content-Type-Options** 223 224 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.<sup>[[3]](#references)</sup> 225 226 ```text 227 X-Content-Type-Options: nosniff 228 ``` 229 230 ### **X-Frame-Options** 231 232 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.<sup>[[3]](#references)</sup> 233 234 ```text 235 X-Frame-Options: DENY 236 ``` 237 238 ### **Cross-Origin Resource Policy (CORP) and Cross-Origin Resource Sharing (CORS)** 239 240 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.<sup>[[3]](#references)</sup> 241 242 ```text 243 Cross-Origin-Resource-Policy: same-origin 244 Access-Control-Allow-Origin: https://example.com 245 Access-Control-Allow-Credentials: true 246 ``` 247 248 ### **Cross-Origin Embedder Policy (COEP) and Cross-Origin Opener Policy (COOP)** 249 250 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.<sup>[[3]](#references)</sup> 251 252 ```text 253 Cross-Origin-Embedder-Policy: require-corp 254 Cross-Origin-Opener-Policy: same-origin-allow-popups 255 ``` 256 257 ### **HTTP Strict Transport Security (HSTS)** 258 259 Lastly, HSTS is a security feature that forces browsers to communicate with servers only over secure HTTPS connections, thereby enhancing privacy and security.<sup>[[3]](#references)</sup> 260 261 ```text 262 Strict-Transport-Security: max-age=3153600 263 ``` 264 265 ### **Permissions-Policy (formerly Feature-Policy)** 266 267 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.<sup>[[4]](#references)[[5]](#references)</sup> 268 269 ```text 270 Permissions-Policy: geolocation=(), camera=(), microphone=() 271 ``` 272 273 **Common directives:** 274 275 | Directive | Description | 276 | --- | --- | 277 | `accelerometer` | Controls access to the Accelerometer sensor | 278 | `camera` | Controls access to video input devices (webcam) | 279 | `geolocation` | Controls access to the Geolocation API | 280 | `gyroscope` | Controls access to the Gyroscope sensor | 281 | `magnetometer` | Controls access to the Magnetometer sensor | 282 | `microphone` | Controls access to audio input devices | 283 | `payment` | Controls access to the Payment Request API | 284 | `usb` | Controls access to the WebUSB API | 285 | `fullscreen` | Controls access to the Fullscreen API | 286 | `autoplay` | Controls whether media can autoplay | 287 | `clipboard-read` | Controls access to read clipboard content | 288 | `clipboard-write` | Controls access to write to the clipboard | 289 290 **Syntax values:** 291 292 - `()` - Disables the feature entirely 293 - `(self)` - Allows the feature only for the same origin 294 - `*` - Allows the feature for all origins 295 - `(self "https://example.com")` - Allows for same origin and specified domain 296 297 **Example configurations:** 298 299 ```text 300 # Restrictive policy - disable most features 301 Permissions-Policy: geolocation=(), camera=(), microphone=(), payment=(), usb=() 302 303 # Allow camera only from same origin 304 Permissions-Policy: camera=(self) 305 306 # Allow geolocation for same origin and a trusted partner 307 Permissions-Policy: geolocation=(self "https://maps.example.com") 308 ``` 309 310 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. 311 312 ## Header Name Casing Bypass 313 314 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.<sup>[[1]](#references)[[8]](#references)</sup> 315 316 Typical situations where this mistake appears: 317 318 * Custom allow/deny lists that try to block “dangerous” internal headers before the request reaches a sensitive component. 319 * In-house implementations of reverse-proxy pseudo-headers (e.g. `X-Forwarded-For` sanitisation). 320 * Frameworks that expose management / debug endpoints and rely on header names for authentication or command selection. 321 322 ### Abusing the bypass 323 324 1. Identify a header that is filtered or validated server-side (for example, by reading source code, documentation, or error messages). 325 2. 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. 326 3. If the downstream component treats headers in a case-insensitive way (most do), it will accept the attacker-controlled value. 327 328 ### Example: Apache Camel `exec` RCE (CVE-2025-27636) 329 330 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. 331 332 ```bash 333 # Bypass the filter by using mixed-case header names and execute `ls /` on the host 334 curl "http://<IP>/command-center" \ 335 -H "CAmelExecCommandExecutable: ls" \ 336 -H "CAmelExecCommandArgs: /" 337 ``` 338 339 The headers reach the `exec` component unfiltered, resulting in remote command execution with the privileges of the Camel process. 340 341 ### Detection & Mitigation 342 343 * Normalise all header names to a single case (usually lowercase) **before** performing allow/deny comparisons. 344 * Reject suspicious duplicates: if both `Header:` and `HeAdEr:` are present, treat it as an anomaly. 345 * Use a positive allow-list enforced **after** canonicalisation. 346 * Protect management endpoints with authentication and network segmentation. 347 348 ## References 349 350 - [1] [CVE-2025-27636 – RCE in Apache Camel via header casing bypass (OffSec blog)](https://www.offsec.com/blog/cve-2025-27636/) 351 - [2] [MDN Web Docs - Content-Disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) 352 - [3] [MDN Web Docs - HTTP headers reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers) 353 - [4] [web.dev - Security headers quick reference](https://web.dev/security-headers/) 354 - [5] [web.dev - Security headers article](https://web.dev/articles/security-headers) 355 - [6] [Bishop Fox - A Crash, Not a Shell: SolarWinds Serv-U CVE-2026-28318](https://bishopfox.com/blog/a-crash-not-a-shell-solarwinds-serev-u-cve-2026-28318) 356 - [7] [BishopFox/CVE-2026-28318-check](https://github.com/BishopFox/CVE-2026-28318-check) 357 - [8] [RFC 9110: HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110.html) 358 - [9] [RFC 9111: HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111.html) 359 - [10] [PortSwigger Research: HTTP/1.1 must die — the desync endgame](https://portswigger.net/research/http1-must-die)