# Exploiting JSONP callback on /username/charts.json endpoint leads to information disclosure despite user's privacy settings

Liberapay's /username/charts.json used jsonp_dump, letting any site read a user's private donation-receiving data via JSONP despite hide_receiving privacy setting.

- Payout: hidden
- Severity: medium
- Program: Liberapay
- Found by: kapytein
- Disclosed: 2018-06-05
- Write-up quality: 6/10
- Original: https://hackerone.com/reports/361951
- Library page: https://bugbountylibrary.com/r/h1%3A361951
- Tags: area:web domain:web impact:data-leak kind:bounty platform:hackerone sev:medium technique:source-review vuln:access-control vuln:info-disclosure vuln:xs-leak

**Target:** /username/charts.json endpoint (JSONP/JSON API)
**Root cause:** The endpoint serves application/json via jsonp_dump, so a cross-origin <script> can invoke a callback and read the response. The hide_receiving 403 check only blocks unauthenticated direct requests, not authenticated cross-site JSONP inclusion.
**Steps:**
1. Host an HTML page containing a script defining `function rip(a){alert(JSON.stringify(a[1]))}`
2. Add `<script src="https://liberapay.com/~153779/charts.json?callback=rip"></script>`
3. Visit the page while authenticated as the target user
4. Callback fires with the JSON array, printing the first row of private receiving-donation data
**How found:** Noticed charts.json.spt used jsonp_dump while the hide_receiving check only guards direct requests; realized JSONP inclusion bypasses the auth-based privacy gate.
**Exploitation:** Attacker lures an authenticated Liberapay user to a malicious page; the JSONP script tag executes the callback with the victim's private charts data, exfiltrating it to the attacker.
**Insight:** When a privacy check depends on the requester's auth state, look for JSONP/callback endpoints on the same data: a cross-site script tag carries the victim's cookies and bypasses the 403.

