# Stored XSS on the "www.intensedebate.com/extras-widgets" url at "Recent comments by" module with malicious blog url

Attacker-controlled blog URL with quote/HTML chars stored unescaped in IntenseDebate 'Recent comments by' widget, executing stored XSS on intensedebate.com user pages.

- Payout: hidden
- Severity: medium
- Program: Automattic
- Found by: superpan
- Disclosed: 2022-04-13
- Write-up quality: 6/10
- Original: https://hackerone.com/reports/1083734
- Library page: https://bugbountylibrary.com/r/h1%3A1083734
- Tags: area:web domain:web impact:ato kind:bounty platform:hackerone sev:medium tech:rest technique:source-review vuln:xss

**Target:** www.intensedebate.com/extras-widgets 'Recent comments by' widget and /widgets/userComment/{id} endpoint
**Root cause:** Blog/site URL is stored without escaping and interpolated into theHTML used for 'Jump to' and 'Document' anchor hrefs, then written via document.write; only the third link is escaped.
**Steps:**
1. Create attacker blog page with route/static file named `"onmousemove=console.log(`Happy-hack!`);>.html` or `"><img+src=z+onerror=console.log(`Happy-hack!`);>.html`
2. Login to intensedebate.com, go to /install, add blog with payload URL e.g. `http://attacker.herokuapp.com/"><img+src=z+onerror=...>.html`
3. Choose Generic Install, complete JS install on attacker blog
4. As victim: login, visit attacker blog, login there, post a comment
5. Visit https://intensedebate.com/extras-widgets and observe payload fires in 'Recent comments by' block
**How found:** Noticed the widget fetches /widgets/userComment/{userID} returning prebuilt HTML; code review of the response showed 'Jump to' and 'Document' hrefs unescaped while a third link was escaped, suggesting inconsistent encoding of the blog URL.
**Exploitation:** Attacker lures victim to comment on attacker's blog; the malicious blog URL is stored and later rendered unescaped in the victim's 'Recent comments by' widget on intensedebate.com, executing arbitrary JS in the intensedebate.com origin to make requests or access user data.
**Insight:** When a widget builds HTML server-side and injects via document.write, compare sibling links in the same template: if one is entity-escaped and another is not, the unescaped one is the injection point, and the stored field (blog URL) is attacker-controlled at registration.
