# Reflected XSS via unescaped request data

Request values echoed into HTML, script, URL, cookie or attribute contexts without encoding for that context

_Area: Web injection and code execution. Seen in 41 disclosed reports; 13 confirmed bounties, median $1,000, range $210-$15,000; latest 2026-02-26. Updated 2026-10-23._

## How it works
A request value (query param, path segment, cookie value, OAuth error/state field, upload filename) is written into a response without encoding for the context it lands in. The broken assumption is that the value is "just data" or "just an error message," but the browser parses the whole response as markup, so a `<`, quote, or event handler in the value becomes live. The sink is often a shared helper or a parallel implementation of one, so the same unescaped write appears in more than one place [E8](https://bugbountylibrary.com/r/h1%3A2520694.md).

## Where it shows up
- Unescaped `uri` param reflected with `text/html` content-type [E2](https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2022-12-gcp-2022-few-bugs-in-google-cloud-shell-html.md)
- Framework helpers marking strings `html_safe`/raw, especially parallel controller vs view implementations [E8](https://bugbountylibrary.com/r/h1%3A2520694.md)
- OAuth callback/error paths reflecting `error_description` or `state` into inline scripts or form_post bodies [E6](https://bugbountylibrary.com/r/h1%3A3424998.md)
- Redirect allowlist domains reflecting `redirect_url` unescaped, including into a form action attribute in an OAuth modal template [E7](https://bugbountylibrary.com/r/h1%3A3081691.md)
- Cookie values reflected into HTML or inline script, settable from a sibling subdomain [E3](https://bugbountylibrary.com/r/h1%3A534450.md)
- Full URL reflected into a canonical `<link href>` allowing attribute injection [E4](https://bugbountylibrary.com/r/h1%3A227486.md)
- Request data reflected into `data-*` attributes; check event-handler injection on hover
- Pagination blocks echoing a param; a sanitizer interacting with a WAF can leave a mangled payload executable
- User-supplied email or profile fields echoed into verification messages [E1](https://bugbountylibrary.com/r/h1%3A2089042.md)
- JSONP/channel-update responses echoing a param into a JS call, where the channel id is not bound to the caller's session [E5](https://bugbountylibrary.com/r/h1%3A259100.md)

## How to review
Find every place request data reaches a response and confirm it is context-encoded — HTML body, attribute, script string, URL, XML, and SVG each need their own encoding (a value safe in a text node is not safe inside a `<script>` string or an `<a href>`). The invariant: no attacker-controlled byte is emitted into markup without encoding for that exact context. Check shared helpers and fallback renderers, not just the happy path [E8](https://bugbountylibrary.com/r/h1%3A2520694.md). For OIDC form_post responses, treat `state` and any reflected field as a sink even when CSP blocks script, since HTML injection alone can exfiltrate embedded tokens [E6](https://bugbountylibrary.com/r/h1%3A3424998.md). For redirect allowlists, check every listed domain for reflected params [E7](https://bugbountylibrary.com/r/h1%3A3081691.md). For cookies, check whether a sibling subdomain can set a cookie scoped to the parent domain [E3](https://bugbountylibrary.com/r/h1%3A534450.md). For JSONP/channel updates, verify the channel id is bound to the caller's session before echoing [E5](https://bugbountylibrary.com/r/h1%3A259100.md).

## Variants seen
- Unescaped `uri` param served as `text/html` [E2](https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2022-12-gcp-2022-few-bugs-in-google-cloud-shell-html.md)
- Framework helper marking error messages/defaults as safe [E8](https://bugbountylibrary.com/r/h1%3A2520694.md)
- OAuth `error_description` reflected into inline script [E6](https://bugbountylibrary.com/r/h1%3A3424998.md)
- Allowlisted redirect domain reflecting a param [E7](https://bugbountylibrary.com/r/h1%3A3081691.md)
- Cookie value reflected into HTML, set via sibling-domain endpoint [E3](https://bugbountylibrary.com/r/h1%3A534450.md)
- Canonical link href attribute injection turned into JS via site click handler [E4](https://bugbountylibrary.com/r/h1%3A227486.md)
- Email field reflected into verification message [E1](https://bugbountylibrary.com/r/h1%3A2089042.md)
- JSONP channel update echoing a param, channel id not session-bound [E5](https://bugbountylibrary.com/r/h1%3A259100.md)

## Why fixes fail
A fix landed in one implementation of a helper but was never ported to its parallel twin, leaving the other path exploitable [E8](https://bugbountylibrary.com/r/h1%3A2520694.md). Fixes that escape one context (text) miss attribute or script contexts [E6](https://bugbountylibrary.com/r/h1%3A3424998.md).

## Impact and severity
Session hijack and account takeover, often as one link in a chain rather than XSS alone [E1](https://bugbountylibrary.com/r/h1%3A2089042.md)[E7](https://bugbountylibrary.com/r/h1%3A3081691.md). Severity rises when the sink is pre-auth and customer-facing, when the origin holds tokens [E6](https://bugbountylibrary.com/r/h1%3A3424998.md), or when a whitelisted redirect domain is forgotten/rebranded [E7](https://bugbountylibrary.com/r/h1%3A3081691.md). HTML injection alone matters when CSP blocks script but tokens sit in the page [E6](https://bugbountylibrary.com/r/h1%3A3424998.md). At Yelp the XSS was one link in an ATO chain that also relied on a cookie bridge [E1](https://bugbountylibrary.com/r/h1%3A2089042.md).

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A2089042.md
- E2: https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2022-12-gcp-2022-few-bugs-in-google-cloud-shell-html.md
- E3: https://bugbountylibrary.com/r/h1%3A534450.md
- E4: https://bugbountylibrary.com/r/h1%3A227486.md
- E5: https://bugbountylibrary.com/r/h1%3A259100.md
- E6: https://bugbountylibrary.com/r/h1%3A3424998.md
- E7: https://bugbountylibrary.com/r/h1%3A3081691.md
- E8: https://bugbountylibrary.com/r/h1%3A2520694.md
