How I De-Anonymized Instagram Users Through Facebook Services

I discovered a vulnerability chain in Instagram and Facebook services that allowed me to de-anonymize Instagram users and retrieve personally identifiable information, including their name, email address, and phone number.

What started as a validation flaw in Instagram's Action Button configuration turned into a series of three related security issues. Facebook attempted to mitigate the original vulnerability twice, and each time I found a different way to restore the same impact.

The three reports were awarded $5,000 each, for a total of $15,000.

Issue Broken server-side validation, Linkshim bypass, referrer leakage, and PII disclosure
Impact De-anonymize an Instagram user and retrieve their name, email address, or phone number
Total Bounty $15,000 across the original issue and two bypasses
Instagram and Facebook de-anonymization vulnerability chain
High-level view of the final Instagram de-anonymization chain.

Instagram Action Buttons

Instagram business accounts could add Action Buttons to their profile. These buttons connected an Instagram profile to services such as appointment booking, ticketing, and reservations.

Instagram Add an Action Button interface
Instagram's Action Button configuration interface.

One of the supported integrations was Appointments by Facebook.

Appointments by Facebook integration for Instagram
Connecting Facebook's appointment service to an Instagram profile.

The Original Vulnerability

When configuring an Action Button, Instagram first called a URL-validation endpoint:

/api/v1/business/instant_experience/ix_validate_url/

The request contained values such as:

app_id
url

This endpoint verified that the supplied URL belonged to the allowed scope of the selected application.

If validation succeeded, Instagram later sent a separate update request to:

/api/v1/accounts/update_business_info/

with fields such as:

ix_url
ix_app_id
is_call_to_action_enabled

The security problem was that the validation and update operations were completely separate.

Instagram validated the URL in ix_validate_url, but the backend responsible for update_business_info did not repeat that validation.

The server effectively trusted the client to only submit the URL that had previously passed validation.

Bypassing URL Validation

Because the update endpoint did not independently validate the URL, the validation response could be manipulated to make the Instagram client generate the final request, but that manipulation was not required for exploitation. The vulnerable update endpoint could also be called directly.

For example, I could intercept the validation request in Burp Suite, manipulate the validation result, and then allow Instagram to generate the final update request.

More importantly, the validation endpoint itself was not required at all. I could simply send the update request directly.

This allowed me to save:

  • Facebook's legitimate App ID for the appointment integration
  • My own attacker-controlled external URL

That combination should never have been accepted.

Why the Facebook App ID Mattered

When a user later clicked the Book button on the Instagram profile, Instagram checked the configured app_id.

Because the App ID belonged to Facebook's own appointment integration, Instagram treated the destination as trusted.

As a result, the normal Instagram Linkshim protection was not shown to the user.

Instead, Instagram navigated directly to my configured URL without showing Linkshim and included the Instagram user identifier in the navigation data.

Instagram Book button using Facebook appointment integration
The Book button appeared as a trusted Facebook-backed Instagram integration.

Turning the Token Into User PII

Once the user reached my server, I extracted the Instagram-related user identifier and passed it to a server-side script.

That script requested Facebook's appointment endpoint:

https://m.facebook.com/services_vertical/book_appointment/
    ?page_id=PAGE_ID
    &ig_ix=true
    &user_id=USER_ID

The response contained structured data related to the Instagram user.

Among the fields exposed by the response were:

  • consumerName
  • consumerEmail
  • consumerPhoneNumber
  • externalUserID
  • platform
  • pageID
Server-side script retrieving Instagram user PII from Facebook appointment endpoint
Proof-of-concept code parsing the Facebook appointment response.

This meant that a user who simply clicked the Book button could potentially be mapped to their real name, email address, or phone number.

Why the Report Was Initially Rejected

Facebook security response initially rejecting the bypass
Facebook initially interpreted the issue as client-side manipulation.

From their perspective, modifying the response from ix_validate_url in Burp looked like changing local application behavior rather than bypassing a security control.

The important distinction was that I was not relying on the manipulated validation response itself for the exploit.

I only manipulated that step to make the Instagram client generate the final update_business_info request.

The actual vulnerability was entirely server-side: the update endpoint accepted an unvalidated URL.

Once that was understood, Facebook accepted the issue.

First Fix

Instagram action button configuration after Facebook UI restriction
The underlying backend functionality remained reachable even after the UI-level restriction.

Facebook's first mitigation did not fix the vulnerable backend logic.

Instead, they removed or restricted Appointments by Facebook so that normal users could no longer select it while creating an Instagram Action Button.

From the user interface, the vulnerable integration was effectively gone.

But the backend still supported it.

First Bypass

I already knew the Facebook App ID used by the appointment integration.

So instead of selecting the integration through the UI, I sent the update_business_info request directly and supplied the original Facebook appointment App ID myself.

The backend still accepted it.

That recreated the same configuration and restored the original vulnerability.

The First Bypass Was Rejected Too

Facebook initially rejected this bypass as well.

The initial review assumed the mitigation was enforced server-side rather than only through the UI.

Facebook security response initially rejecting the bypass
Facebook initially disagreed that the appointment restriction could be bypassed this way.

I sent additional proof-of-concept material demonstrating that the backend still accepted the Facebook App ID directly and that the vulnerable Action Button could still be created without using the UI.

Facebook eventually reproduced the bypass and accepted the report.

Second Fix: Server-Side URL Validation

After the first bypass, Facebook implemented the validation that should have existed from the beginning.

The update endpoint now verified that a URL associated with the Facebook appointment App ID belonged to an allowed Facebook domain.

My external domain could no longer be saved directly.

At this point, simply calling the update endpoint was no longer enough.

I needed a URL that:

  • belonged to an allowed Facebook domain
  • could eventually redirect the user toward infrastructure I controlled
  • preserved the Instagram token during navigation

Looking at Referrer Policy

The token was present in the navigation URL, so browser referrer behavior became important.

A restrictive Referrer-Policy can prevent the full path and query string from being disclosed during cross-origin navigation.

origin-when-cross-origin and strict-origin-when-cross-origin referrer policies
Referrer policy determines how much of the previous URL is sent to another origin.

I wrote a small script to scan Facebook subdomains looking for hosts that did not enforce the expected restrictive referrer policy.

Script scanning Facebook subdomains for referrer policy behavior
Scanning Facebook-controlled domains for useful referrer-policy behavior.

Finding Facebook Workplace

The scan led me to:

fb.m.facebook.com

This was a trusted Facebook subdomain used by Facebook Workplace.

Facebook Workplace mobile endpoint
The Facebook Workplace host that became part of the second bypass.

One Workplace language-selection endpoint accepted a destination through an n parameter.

A request looked conceptually like:

https://fb.m.facebook.com/language.php?n=FACEBOOK_URL

The destination was restricted to Facebook-controlled domains, which normally would have made the redirect harmless.

Facebook Workplace language endpoint with redirect destination
The Workplace language-selection flow carrying another Facebook URL in the destination parameter.

Preserving the Referrer

The important part was that this Workplace endpoint did not apply the referrer policy that would have removed the sensitive path and query string.

Facebook Workplace source showing referrer configuration
The Workplace page did not provide the same referrer protection expected elsewhere in the chain.

When the victim clicked one of the language options, the browser navigated to the URL supplied in n.

Because of the referrer behavior, the previous URL — including the information passed from Instagram — could continue through the next navigation step.

Chaining a Facebook Redirect

The next problem was escaping from the Facebook-only destination restriction.

I already had another Facebook-controlled redirect behavior from separate research.

I used that redirect as the next hop in the chain. I am intentionally not documenting that unrelated endpoint in detail here.

Conceptually, the navigation became:

Instagram
    ↓
fb.m.facebook.com/language.php?n=FACEBOOK_REDIRECT
    ↓
facebook.com/...
    ↓
fbcdn.net/...

The Facebook redirect accepted fbcdn.net as a trusted Facebook destination.

Because the intermediate pages did not apply a restrictive referrer policy, the sensitive path and query information survived the next navigation step.

Facebook Workplace Facebook CDN redirect chain
The cross-domain chain used to preserve the Instagram navigation information.

Attacker-Controlled HTML on fbcdn.net

I had also found a way to host attacker-controlled HTML on a Facebook CDN origin.

That gave me executable content under fbcdn.net, which was already accepted as a trusted destination by the preceding Facebook redirect.

Attacker controlled HTML executing from Facebook CDN
Attacker-controlled HTML hosted on a Facebook CDN origin.

The HTML page read document.referrer.

Because the previous redirects had preserved the full referrer, the page could recover the information originally passed from Instagram.

The page then forwarded that value to my own server.

Restoring the Original PII Disclosure

Once my server received the Instagram user identifier again, the final step was exactly the same as in the original vulnerability.

My script submitted the identifier to:

https://m.facebook.com/services_vertical/book_appointment/
    ?page_id=PAGE_ID
    &ig_ix=true
    &user_id=USER_ID

The Facebook appointment response once again exposed the user's associated information.

The full second-bypass chain was therefore:

  1. The victim clicks the Instagram Book button.
  2. Instagram opens the allowed fb.m.facebook.com Workplace URL with the user identifier embedded in the URL.
  3. When the user chooses a language, the browser sends that full URL as the referrer to the next Facebook-controlled hop.
  4. The Workplace language endpoint preserves the sensitive referrer.
  5. The victim selects a language and is redirected to another Facebook-controlled endpoint.
  6. That endpoint redirects to a trusted fbcdn.net destination.
  7. Attacker-controlled HTML on fbcdn.net reads the full referrer.
  8. The HTML sends the recovered identifier to my server.
  9. My server queries the Facebook appointment endpoint.
  10. The Instagram user's PII is returned.
Facebook bounty response confirming Instagram email and phone disclosure
Facebook bounty awards for two successive bypasses of the original vulnerability.
Original Issue Missing server-side URL validation in the Action Button update flow — $5,000
First Bypass Directly reusing the hidden/restricted Facebook appointment App ID — $5,000
Second Bypass Facebook-domain validation bypass through Workplace, referrer propagation, Facebook redirects, and fbcdn.net — $5,000
Total $15,000

Conclusion

The most interesting part of this research was how the vulnerability evolved after each mitigation.

The original bug was fundamentally a server-side validation inconsistency: Instagram validated the Action Button URL in one endpoint but trusted the client when the same data reached the update endpoint.

Facebook's first mitigation addressed the visible feature rather than the underlying trust boundary, so directly calling the backend restored the vulnerability.

The second mitigation correctly introduced server-side URL validation, but the broader Facebook ecosystem still provided enough primitives to rebuild the attack through trusted domains.

By combining a Workplace redirect flow, weak referrer handling, another Facebook-controlled redirect, trusted CDN infrastructure, and attacker-controlled content on that CDN, I was able to recover the Instagram identifier and reach the original PII-disclosure endpoint again.

For me, this research was a good demonstration of a recurring security lesson: fixing the immediate vulnerable path does not necessarily eliminate the exploit when equivalent trust relationships remain elsewhere in the system.