# Make API calls on behalf of another user (CSRF protection bypass)

Vimeo API playground's only CSRF defense was an X-Requested-With header, bypassed via Flash 307 redirect to issue API calls as the logged-in user.

- Payout: hidden
- Severity: high
- Program: Vimeo
- Found by: avlidienbrunn
- Disclosed: 2015-01-22
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/44146
- Library page: https://bugbountylibrary.com/r/h1%3A44146
- Tags: area:web domain:web impact:integrity kind:bounty platform:hackerone sev:high tech:rest technique:chained vuln:auth-bypass vuln:csrf

**Target:** API playground endpoint /api/playground/me
**Root cause:** The playground relied solely on the presence of an X-Requested-With: XMLHttpRequest header for CSRF protection, assuming cross-domain AJAX could not set it. Flash can set the header and a 307 redirect from an allowed domain causes Flash to send the request before fetching crossdomain.xml on the target.
**Steps:**
1. Log in to Vimeo in Safari
2. Visit `https://s3.amazonaws.com/avlidienbrunn/vimeo_pwn.swf`
3. SWF loads `https://avlidienbrunn.se/crossdomain.xml`
4. SWF requests `https://avlidienbrunn.se/vimeo_pwn.php` which returns a 307 redirect to the Vimeo API playground
5. Flash follows the redirect to `https://developer.vimeo.com/api/playground/me` including the `X-Requested-With` header, issuing the API call as the victim
6. Profile biography is changed to `avlidienbrunn+was+here`
**How found:** Observed the playground's CSRF protection was only the X-Requested-With header, reasoned that CORS blocks cross-domain AJAX but Flash can set the header, then found that a 307 redirect from an allowed domain makes Flash send the request before requesting crossdomain.xml on the new domain.
**Exploitation:** Attacker hosts a malicious SWF on S3 and a redirector on a domain with a permissive crossdomain.xml. The SWF sends a request with the X-Requested-With header to the attacker's redirector, which 307-redirects to the Vimeo API playground. Flash follows the redirect and sends the header before checking the target's crossdomain.xml, so the authenticated API call executes. Response cannot be read, limiting impact to state-changing calls.
**Insight:** When a target's only CSRF defense is a custom header like X-Requested-With, look for legacy plugin vectors (Flash/Silverlight) that can set arbitrary headers, and use a 307 redirect from a domain with a permissive crossdomain.xml to bypass the SOP check ordering.

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

**PoC SWF URL that changes victim's biography**

```
1. Log in to Vimeo in Safari
2. Visit https://s3.amazonaws.com/avlidienbrunn/vimeo_pwn.swf
3. Your profile biography now says "avlidienbrunn+was+here"
```

**307 redirect request sequence to bypass CSRF**

```
1. Safari requests https://s3.amazonaws.com/avlidienbrunn/vimeo_pwn.swf
2. SWF requests https://avlidienbrunn.se/crossdomain.xml
3. SWF requests https://avlidienbrunn.se/vimeo_pwn.php (issues 307 redirect to Vimeo API playground)
4. SWF requests https://developer.vimeo.com/api/playground/me (including the X-Requested-With header)
5. SWF requests https://developer.vimeo.com/crossdomain.xml
```

