daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

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, '&lt;').replace(/>/g, '&gt;');
    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)