# Gaining access to private topics using quoting feature

Discourse onebox preview trusted a user-supplied source_topic_id query param, letting any user read staff-only private topic content via link preview.

- Payout: $256
- Severity: high
- Program: Discourse
- Credited: mishre
- Disclosed: 2018-03-17
- Write-up quality: 7/10
- Original: https://hackerone.com/reports/312647
- Library page: https://bugbountylibrary.com/r/h1%3A312647
- Tags: domain:web impact:data-leak kind:bounty platform:hackerone sev:high tech:ruby technique:source-review vuln:access-control vuln:idor vuln:info-disclosure

**Target:** Discourse local onebox link-preview endpoint
**Root cause:** can_see_topic?/can_see_post? fall back to same_category?(topic.category, source_topic), and source_topic is derived from the attacker-controlled `source_topic_id` URL parameter, so pointing it at the victim topic makes the category check trivially pass.
**Steps:**
1. As admin, create a staff-only private topic; note its id from `/t/{slug}/{id}`.
2. As a non-admin user, post a reply containing `http://localhost:80/t/blablabla/?source_topic_id=29` (port must be 80/443).
3. Wait for the onebox preview to render; the private topic content is disclosed.
**How found:** Code review of the onebox access-check logic: noticed source_topic was parsed from the URL rather than derived server-side, and that same_category? short-circuits the Guardian check when source and target match.
**Exploitation:** Attacker with any posting ability submits a link to the private topic with `?source_topic_id={victim-topic-id}`; the onebox fetches and renders the preview, bypassing Guardian access checks and leaking the private topic/post body.
**Insight:** When an access check compares a target against a 'source' context, verify that context is server-derived, not attacker-supplied; any user-controlled parameter feeding a same-X comparison is a bypass.
