# yelp.com and biz.yelp.com ATO via XSS + Cookie Bridge

Unverified business email reflected into a verify-email message yields XSS; chained with Yelp's cookie bridge and cookie-size DoS to leak HttpOnly session cookies and take over accounts.

- Payout: hidden
- Severity: medium
- Program: Yelp
- Found by: lil_endian
- Disclosed: 2023-09-08
- Write-up quality: 9/10
- Original: https://hackerone.com/reports/2089042
- Library page: https://bugbountylibrary.com/r/h1%3A2089042
- Tags: area:web domain:web impact:ato impact:data-leak kind:bounty platform:hackerone sev:medium tech:nginx technique:chained technique:source-review vuln:xss

**Target:** biz.yelp.com email verification page and cookie_bridge endpoints
**Root cause:** The unverified business email is reflected unescaped into the verify-email message, allowing an attacker-chosen email containing an iframe/onload payload to execute JS. The cookie bridge's one-time cookie_fsid token can be prevented from being consumed by overflowing the cookie header, leaving the retrieve URL readable via window.opener.
**Steps:**
1. Register business account with email `"<iframe/onload=eval(atob(location.hash.substring(1)))>"@calc.sh` and leave unverified.
2. Request `https://biz.yelp.com/cookie_bridge/store?dhl=da_DK&redir=/home/%23<base64 payload>` to get a 303 to `https://biz.yelp.dk/cookie_bridge/retrieve?cookie_fsid=...&redir=...`.
3. Victim opens attacker page which window.open()s the retrieve URL; XSS fires in Tab B on biz.yelp.dk.
4. Payload sets 16 cookies `X0..X15` of 1000 chars each with `path=/cookie_bridge/retrieve` to make openresty reject requests with 400.
5. Payload postMessages opener to navigate Tab A to `https://biz.yelp.com/cookie_bridge/store?dhl=da_DK`; store fails with 400 so cookie_fsid is not consumed.
6. Tab B reads `window.opener.location.href` (same origin biz.yelp.dk) to obtain the victim's retrieve URL; attacker visits it to be signed in as victim.
**How found:** Noticed the unverified email is reflected in the verify-email banner and that a 64-char email limit still permits an iframe/onload payload; then reasoned about the cookie bridge's one-time cookie_fsid and hypothesized that forcing the store request to fail would leave the token unconsumed and readable cross-tab.
**Exploitation:** Attacker lures victim to a page that opens the cookie-bridge retrieve URL carrying the XSS payload in the fragment, signing the victim into the attacker's biz.yelp.dk session where the payload executes. The payload inflates cookies on the retrieve path to force a 400 on the store step, preventing one-time token consumption, then reads the opener's retrieve URL to hijack the victim's HttpOnly session cookies for both business and regular accounts.
**Escalation:** Self-XSS escalated to reflected XSS in victim session via cookie bridge, then to HttpOnly session theft via cookie-size DoS on the one-time token, enabling full ATO of business and normal accounts.
**Insight:** One-time token endpoints that consume the token on retrieval can be defeated by making the consuming request fail (e.g. oversized Cookie header causing 400) so the token stays valid and leaks via window.opener; also, short reflected fields like emails can still fit compact iframe/onload XSS payloads.
