Full Report
Instagram allows for the embedding of posts. When embedding a post, it's simply a popup with embedded HTML that makes a request to https://www.instagram.com/api/v1/oembed/. This will get the post information, author, title and several other things. If this is provided from a private account, then a 403 is sent back. If the account of the post is blocked and is private, then the response will be 404 not found. This is a perfect case for XS-leaks! Within the iFrame, if an error occurs, then the account was blocked and is part of a subset of users. This creates a de-anonymization primitive for users of a website using Instagram, which is not great. So, a medium severity bug. As any good bug bounty hunter does, they were gathering evidence and testing things out. While making this call with Burp repeater, Burp and Chrome were doing different things. What's going on? It turns out that the user-agent header was being processed. After fuzzing the header, they noticed that the code being ran on mobile was different than in the browser. So, by blocking the user and making a request to the private account, the embedded endpoint was returning data! According to Meta, the oEmbed endpoint had an error case for mobile agents. This error was normally triggered by region blocking but the developers wanted all users to be able to access the items even when this error occurred. To fix this, a superuser was used to make the request instead. By blocking the user, the generic error handler was possible to hit as well! This allowed for us to access the post, even though we'd been rejected from it. Overall, a super unique vulnerability that required a lot of puzzle pieces to make happen. To me, the big takeaway is that unexpected functionality should always be explored deeper.
Analysis Summary
# Vulnerability: Instagram Private Post Disclosure via oEmbed Mobile Agent Bypass
## CVE Details
- **CVE ID**: Not explicitly assigned in report (Internally tracked by Meta)
- **CVSS Score**: Medium (Estimated 6.5 - 7.5 range)
- **CWE**: CWE-285 (Improper Authorization), CWE-203 (Observable Response Discrepancy)
## Affected Systems
- **Products**: Instagram (Web and Mobile API)
- **Versions**: All versions prior to November 2022
- **Configurations**: Specific to the `api/v1/oembed/` endpoint when accessed with mobile User-Agent headers.
## Vulnerability Description
The vulnerability stems from a logic flaw in how Instagram’s oEmbed endpoint handled errors for mobile clients.
1. **XS-Leak Primitive**: By default, the oEmbed endpoint returned different HTTP status codes (403 for private accounts, 404 for blocked accounts). This allowed for de-anonymization via side-channel attacks.
2. **User-Agent Logic Fork**: The application processed requests differently based on the `User-Agent` header. Requests appearing to come from mobile devices hit a specific error-handling route.
3. **Superuser Privilege Escalation**: In the mobile route, if an error occurred (specifically designed to handle region-blocking restrictions), the system was configured to retry the request using a "superuser" account to ensure the embed remained functional.
4. **The Flaw**: By intentionally blocking the target user and then requesting their private post with a mobile User-Agent, the attacker triggered the generic error handler. This caused the system to invoke the superuser account, which bypassed privacy settings and returned the private post data (including CDN links to media) to the attacker.
## Exploitation
- **Status**: PoC available (demonstrated to Meta during BountyCon)
- **Complexity**: High (Requires chaining XS-Leaks, specific User-Agent fuzzing, and the "blocking" state)
- **Attack Vector**: Network
## Impact
- **Confidentiality**: High (Allows unauthorized viewing of private posts, captions, and media URLs)
- **Integrity**: None
- **Availability**: None
## Remediation
### Patches
- Meta deployed a server-side fix in late 2022 to the `api/v1/oembed/` endpoint logic. The superuser bypass was restricted or removed from this specific error handler.
### Workarounds
- There are no user-side workarounds other than disabling the ability for others to embed your posts (if that setting is available) or deleting sensitive private content.
## Detection
- **Indicators of Compromise**: Repeated requests to the `oembed` endpoint for private profiles from an account that has been blocked by those profiles.
- **Detection methods**: Internal monitoring for "Superuser" account activity originating from public-facing API endpoints.
## References
- **Vendor Advisory**: Meta Bug Bounty Program (BountyCon 2022)
- **Original Writeup**: `https://003random[.]com/posts/meta-bountycon-instagram-writeup/`
- **XS-Leaks Documentation**: `https://xsleaks[.]dev/`