I discovered a vulnerability in Facebook Creative Hub that allowed an attacker to create an invisible (unlisted) post on an arbitrary Facebook Page without having a role on that Page.
The issue was caused by a missing authorization check when Creative Hub generated preview posts through its sharing workflow. Facebook fixed the original vulnerability after my report, but I later found a second path that bypassed the initial fix.
| Product | Facebook Creative Hub |
|---|---|
| Issue | Missing authorization / access-control validation |
| Impact | Create an invisible post on an arbitrary Facebook Page |
| Reported | November 6, 2020 |
| Final fix | November 20, 2020 |
| Bounty | $30,000 |
Background
Facebook supports different types of posts. One of them is an invisible, or unlisted, post. Unlike a normal Page post, it does not appear on the Page timeline, but it still has its own post ID and direct URL.
Because the post is not visible on the normal Page timeline, a Page administrator may not discover it through the usual Page interface. The post can still be accessed directly and shared with other users.
Creative Hub and Preview Posts
Facebook Creative Hub allowed advertisers to create ad mockups and collaborate on them. To preview a mockup, Facebook generated an invisible post on the selected Page.
While testing this workflow, I intercepted the request responsible for saving the mockup and changed the page_id to the ID of another Page. The modified request was accepted and saved without an authorization error.
There was an authorization check in the normal preview-generation flow: a user was expected to have an advertiser role on the selected Page before Facebook would generate the preview.
The Missing Authorization Check
Creative Hub also had a sharing feature for ad previews. After clicking Share, the API returned a shareable preview URL in this format:
https://www.facebook.com/ads/previewer/__PREVIEW_KEY__
The important difference was that the authorization check was missing when a preview post was generated through the share page.
By changing the page_id in the GraphQL request before saving the mockup, then obtaining the shareable preview URL, it was possible to make Facebook generate a preview post associated with an arbitrary Page.
The remaining step was to obtain the resulting post_id, which was exposed through the ad-preview endpoints. This completed the chain and produced an invisible post on the target Page without the Page owner's knowledge.
Proof of Concept
Bypassing the Initial Fix
Facebook fixed the original vulnerability after I reported it. During verification, however, I found another Creative Hub workflow that could still generate the preview without performing the required Page permission check.
The Send to Mobile functionality called the following endpoint:
AsyncRequest.post('/ads/previewer/notify_mobile/__PREVIEW_KEY__', {})
Calling this functionality caused Facebook to generate the preview again and send a notification to the mobile device. The preview-generation step in this path did not enforce the expected Page authorization check, which allowed the original issue to be reproduced through a different workflow.
Bypass Proof of Concept
Disclosure Timeline
| November 6, 2020 | Initial vulnerability reported to Facebook. |
|---|---|
| November 6, 2020 | Report triaged. |
| November 11, 2020 | Initial vulnerability fixed. |
| November 12, 2020 | Fix bypass reported. |
| November 12, 2020 | Bypass triaged. |
| November 20, 2020 | Bypass fixed. |
| December 16, 2020 | $30,000 bounty awarded. |
This comment has been removed by a blog administrator.
ReplyDelete