Full Report
The web browser attempts to isolate all pages by default but allows some cross-domain communication. An interesting, yet new to me, method is by using the hash. This has been documented for a long time but was not something that I knew about. The hash of a given page can be changed by something with a completely different domain. The twitter post uses window.open on the target window in order to do this. The post I linked above from WellCaffeinated does this by simply setting the frame source. Why is this useful? Some pages do routing based upon the hash or use it in some other way. Being able to trigger this cross-domain can be used to have crazy effects. This is a short note but something that I wanted to remember for later.
Analysis Summary
# Vulnerability: Cross-Origin `onhashchange` Triggering via `window.open`
## CVE Details
- **CVE ID:** Not assigned (This is a documented browser behavior used as an exploitation "gadget" rather than a specific software flaw).
- **CVSS Score:** N/A (Severity depends on the implementation of the target application).
- **CWE:** CWE-441: Confused Deputy; CWE-20: Improper Input Validation.
## Affected Systems
- **Products:** Standard Web Browsers (Chrome, Firefox, Safari, Edge).
- **Versions:** Most modern versions following current HTML5 specifications regarding the Fragment Identifier.
- **Configurations:** Web applications that utilize `onhashchange` event listeners or fragment-based routing (`#`) to perform sensitive actions without secondary validation.
## Vulnerability Description
This technique leverages a standard browser behavior where a parent window (or any window with a reference to a target window) can change the URL hash of a cross-origin page. By calling `window.open` with a specific URL including a new hash fragment (e.g., `window[.]open("https://victim[.]com/path#newhash", "targetWindowName")`), the browser does not reload the page if the base URL matches, but it *does* trigger the `onhashchange` event within the target window.
If the target application uses the hash for client-side routing, state management, or triggering specific JavaScript functions (gadgets), an attacker can force the application into an unintended state from a malicious site.
## Exploitation
- **Status:** PoC available (Technique documented by security researchers @joaxcar and @ctbbpodcast).
- **Complexity:** Low (Requires knowing the target's full path and the name of the target window).
- **Attack Vector:** Network (Web-based/Cross-origin).
## Impact
- **Confidentiality:** Low to Medium (May lead to data exposure if the hash controls sensitive views).
- **Integrity:** Medium (Can trigger unauthorized client-side actions or UI manipulation).
- **Availability:** Low (Typically does not result in a Denial of Service).
## Remediation
### Patches
- No browser patch is expected as this is intended behavior. Developers must secure their applications against fragment-based attacks.
### Workarounds
- **Hash Validation:** Explicitly validate the contents of `location.hash` before using it in logic.
- **Frame Busting/CSP:** Use `Content-Security-Policy: frame-ancestors 'none'` or `'self'` to prevent iframe-based hash manipulation.
- **Secondary Checks:** Do not use hash changes to trigger sensitive state changes (like deletions or privilege escalations) without an additional anti-CSRF token or user interaction.
- **COOP/COEP:** Implement Cross-Origin Opener Policy (`COOP`) headers to prevent other windows from maintaining a reference to your window.
## Detection
- **Indicators of compromise:** Frequent, unexpected `hashchange` events in browser logs or analytics that do not originate from user interaction.
- **Detection methods and tools:** Audit client-side JavaScript for `window.addEventListener('hashchange', ...)` and trace how the fragment data is utilized.
## References
- [x[.]com/ctbbpodcast/status/1789720951392706740]
- [wellcaffeinated[.]net/articles/2012/06/05/cross-domain-communication-with-iframes-part-2-the-location-hash/]
- [developer[.]mozilla[.]org/en-US/docs/Web/API/Window/hashchange_event]