# Opportunity to obtain private tweets through search widget preview caches

Twitter search widget preview cached results keyed on a varying JSONP callback name, letting an attacker replay cached tweets from users who later went private or deleted them.

- Payout: $1,120
- Severity: medium
- Program: X / xAI
- Credited: csanuragjain
- Disclosed: 2017-11-11
- Write-up quality: 7/10
- Original: https://hackerone.com/reports/263760
- Library page: https://bugbountylibrary.com/r/h1%3A263760
- Tags: domain:web impact:data-leak impact:integrity kind:bounty platform:hackerone sev:medium technique:recon vuln:business-logic vuln:cache-deception vuln:info-disclosure

**Target:** twitter.com /widgets/timelines/preview JSONP endpoint
**Root cause:** The preview endpoint cached responses despite no-cache headers, and the cache key included the JSONP callback name (__twttr.callbacks.tl_i<N>_preview_old), so varying N exposed stale cached snapshots of tweets that were later made private or deleted.
**Steps:**
1. Navigate to `https://twitter.com/settings/widgets/new` and search a target username (e.g. `countblank`).
2. Intercept the request to `/widgets/timelines/preview?all_results=on&callback=__twttr.callbacks.tl_i<N>_preview_old&...&query=<user>&timeline_type=search`.
3. Add header `Accept-Encoding: gzip, deflate, br` to force cached response.
4. Iterate callback number `i1`..`i1000` in `__twttr.callbacks.tl_i<N>_preview_old`; each distinct callback yields a different cached snapshot.
5. Collect responses containing tweets from the now-private/deleted account.
**How found:** Noticed the widget preview returned more tweets than expected for a private profile, and that the JSONP callback name varied per request, hypothesizing the cache key included it; adding Accept-Encoding forced cache hits and iterating the callback index surfaced stale snapshots.
**Exploitation:** Attacker enumerates callback indices to retrieve cached preview responses containing tweets that were public at cache time but are now private or deleted, bypassing the privacy change.
**Insight:** When a JSONP/JSON endpoint embeds a per-request callback name in the URL, test whether the CDN/cache keys on the full URL — varying the callback index can enumerate stale cached snapshots of data that has since changed visibility.
