# Angular Client Hydration DOM Clobbering & Response-Cache Poisoning

Angular hydration looks up state via predictable `ng-state` ID; attacker-clobbered element poisons TransferState HTTP cache, forging API responses leading to XSS or privilege escalation.

- Payout: Research
- Severity: high
- Program: Angular
- Found by: SkyZeroZx
- Disclosed: 2026-06-15
- CVE: CVE-2026-54267
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-rgjc-h3x7-9mwg
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-rgjc-h3x7-9mwg
- Tags: area:os domain:browser domain:web impact:integrity impact:privesc kind:research platform:ghsa sev:high tech:nodejs technique:source-review vuln:cache-poisoning vuln:xss

**Target:** Angular client hydration / TransferState (SSR bootstrap)
**Root cause:** Hydration recovers serialized state by `document.getElementById('ng-state')`, a predictable ID; attacker-controlled elements bound to user input can clobber it before the genuine script parses, so Angular parses attacker JSON as TransferState.
**Steps:**
1. Application binds untrusted input to an element id, e.g. `<div [id]="userInput">` or `<a id="ng-state">`, rendered before the genuine `<script id="ng-state">`.
2. Attacker sets id to `ng-state` and supplies JSON content mapping a target API URL key to a forged response body.
3. During client bootstrap Angular calls `document.getElementById('ng-state')`, gets the clobbered element, and parses its content as JSON into TransferState.
4. `HttpClient` checks TransferState before requesting; finding the poisoned key it returns the forged response instead of calling the backend.
5. Rendered poisoned fields yield DOM XSS, spoofed user/session data, or hijacked config endpoints.
**How found:** Noticed the state container is located solely by a predictable ID (`ng-state`) via getElementById, making it clobberable by any earlier element with the same id bound to user input.
**Exploitation:** Attacker needs a user-controlled id binding rendered before the real state script; injects a clobbered `ng-state` element with JSON keyed by a target API URL and a forged body, which Angular's HttpClient serves as the cached response, enabling XSS or privilege escalation depending on how the app renders that endpoint's data.
**Escalation:** Poisoning arbitrary API endpoint keys in TransferState escalates from cache forgery to XSS, privilege escalation via spoofed user info, or UI hijacking via spoofed config endpoints.
**Insight:** Any framework hydration/state-recovery step that resolves its container by a fixed, predictable DOM id is clobberable — check whether user-bound `id` attributes can precede the genuine serialized-state script and whether the parsed state feeds a response cache.

