Full Report
The author of this post decided to take a look at the Range header. In HTTP, the Range Header is used for returning only changes to the content of a page by requesting partial information on the request by a portion of the header. For instance, you can ask for bytes 2-6 from the request. The other insight is that most browsers will happily render 206 Partial Content queries. To me, this is fairly surprising, since it should be made to get the data only and not be rendered. Putting these two concepts together, if an attacker can get a particular content range to be used in the request with the Range header, the reflected input can be used to get XSS! The post focuses on getting a header injection vulnerability on the request in order to exploit this. I had personally never seen this trick so I thought it was pretty fun. It's weird to me that modern browsers will render the 206 request but every other part of it makes sense.
Analysis Summary
# Vulnerability: Reflected XSS via Range Header Manipulation
## CVE Details
- **CVE ID:** N/A (General technique/Pattern)
- **CVSS Score:** N/A (Dependent on target application implementation)
- **CWE:** CWE-79 (Cross-site Scripting), CWE-113 (HTTP Response Splitting/Header Injection)
## Affected Systems
- **Products:** Web applications and servers supporting the HTTP `Range` header.
- **Versions:** Platform-independent; affects any server-side logic that reflects input and honors range requests.
- **Configurations:**
- Endpoints that reflect user input (even if typically "safe" due to context like being inside an attribute).
- Servers configured to return `206 Partial Content` responses.
- Browsers that render `206 Partial Content` responses as HTML/JavaScript.
## Vulnerability Description
This technique leverages the HTTP `Range` header to isolate reflected input from its surrounding context. In a typical reflected XSS scenario, an attack might fail if the input is reflected inside a "safe" area, such as a quoted string or a JavaScript variable where tags cannot be escaped.
By combining this with **Header Injection** or **Request Desync**, an attacker can inject a `Range` header specifying exactly the byte offset where their input is reflected. The server then responds with a `206 Partial Content` status, serving *only* the attacker's payload. Because modern browsers may still render these partial responses, the previously "trapped" input is now executed as the primary content of the page, bypassing original syntax constraints.
## Exploitation
- **Status:** PoC available (Technique documented)
- **Complexity:** Medium (Requires identifying byte offsets and a method to inject headers/desync requests)
- **Attack Vector:** Network
## Impact
- **Confidentiality:** High (Session hijacking via cookie theft)
- **Integrity:** High (Ability to perform actions on behalf of the user)
- **Availability:** Low
## Remediation
### Patches
- **Application Logic:** Ensure all reflected input is properly encoded for its context, regardless of whether it appears exploitable.
- **Server Configuration:** If partial content is not required for a specific API endpoint, disable support for the `Range` header.
### Workarounds
- **Header Sanitization:** Strip or validate the `Range` header on the server side for sensitive endpoints.
- **Content-Encoding:** Force safe `Content-Type` headers (e.g., `application/json` or `text/plain`) and use `X-Content-Type-Options: nosniff` to prevent browsers from interpreting partial responses as HTML.
## Detection
- **Indicators of Compromise:**
- Unusual `Range` header values (e.g., `Range: bytes=80-99`) in logs for non-media endpoints.
- Requests missing `Accept-Encoding` headers in combination with specific `Range` requests.
- **Detection Methods:** Monitor for `206 Partial Content` status codes on endpoints that typically serve dynamic content or JSON rather than static files.
## References
- hxxps[://]attackshipsonfi[.]re/p/exploiting-reflected-input-via-the
- hxxps[://]developer[.]mozilla[.]org/en-US/docs/Web/HTTP/Headers/Range