Animation-based tapjacking on Custom Tabs
Categories
(Firefox for Android :: General, defect, P2)
Tracking
()
People
(Reporter: philipp.beer, Assigned: boek)
References
Details
(Keywords: csectype-clickjacking, reporter-external, sec-high, Whiteboard: [fxdroid][group1][adv-main136+])
Attachments
(5 files)
|
7.92 MB,
video/mp4
|
Details | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
1 byte,
text/plain
|
tjr
:
sec-approval+
|
Details |
|
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-beta+
|
Details | Review |
|
311 bytes,
text/plain
|
Details |
Steps to reproduce:
Attack Summary
We discovered a vulnerability in which an Android app without any permissions can exploit animations and launch a Firefox Custom Tab (CT) to bypass permission checks on websites and perform clickjacking attacks against arbitrary websites.
Primitives
Android applications can use Custom Tabs (CT) to open web content with minimal context switching, as Custom Tab Activities are launched within the same task as the requesting application. Through the ActivityOptions.makeCustomAnimation method, Android also allows applications to specify custom enter and exit animations for cross-activity and same-task transitions, such as the transition between an app and a Firefox CT.
An application installed on the user's device can exploit this functionality by launching a Custom Tab and setting an enter animation with a long fade-in duration, set to low opacity. This transition brings the Custom Tab to the foreground yet keeps it invisible to the user while the animation completes since the CT is basically transparent (e.g., opacity=0.0005). As the CT Activity is on top of the stack, and Firefox does not wait for animations to be finished before handling touches, screen interactions are handled by the browser.
The following minimum working example demonstrates this exploit, assuming Firefox is the default browser:
MainActivity.kt
val builder = CustomTabsIntent.Builder()
// setStartAnimation internally uses ActivityOptions#makeCustomAnimation
builder.setStartAnimations(this, R.anim.fade_in, R.anim.fade_out)
val customTabsIntent = builder.build()
customTabsIntent.launchUrl(this, victimUrl)
res/anim/fade_in.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Long-running animation with low opacity -->
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="0.0"
android:toAlpha="0.0005"
android:duration="20000"/>
res/anim/fade_out.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- This boils down to no animation, as duration = 0 -->
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="1.0"
android:toAlpha="1.0"
android:duration="0" />
This report is part of a coordinated responsible disclosure on the underlying animation-based tapjacking vulnerability that we discovered on Android.
Impact
The vulnerability opens doors for the following Web-specific issues:
- Permission Bypass
By launching a CT with this technique, an application can open an attacker-controlled website that requests sensitive permissions, such as microphone or camera access. By luring the user to tap a button that is positioned at the same location as the allow button in the permission prompt, the permission is granted to the website without user awareness. Since CT permissions are shared with Firefox, any permissions granted in this way go beyond the CT, granting persistence to the attacker in the victim's browser.
- Web Clickjacking Attacks
An app can secretly request a website, i.e, a checkout page of an online store, and lure the user into performing critical actions, such as clicking the 'buy' button. Existing standard web-based clickjacking peventions, such as the Content Security Policy frame-ancesters directive and the X-Frame-Options headers do not apply here and do not mitigate these attacks.
Practicality of the Attack
A slow fade-in transition would reveal the Firefox window after a few seconds, but an app can re-launch its own activity before the animation ends to effectively hide the Custom Tab. A delay of 2500ms between starting the CT and re-launching the activity of the app is effective according to our experiments. This means that the permission prompt is clickable for 2.5s. Although this is a rather short time frame for user interaction, attack scenarios like games, where users are prompted to tap quickly, make this attack practical.
Actual results:
Touches while the animation is running and the Firefox activity is essentially invisible are handled by Firefox.
We created a proof of concept application that demonstrates how to bypass the Firefox permission prompt via tapjacking. Additionally, we attached a video demonstrating the attack.
Notice that the button positioning is manually adjusted for a Pixel 6a and might require some tweaking to generalize to different devices.
The application opens https://webrtc.github.io/test-pages/src/iframe-video/, which immediately on load requests for the camera permission.
To replicate the permission tapjacking, follow these steps:
- Grant Firefox permission to access the user's camera
- Install the PoC application (find the source code here)
- Click "Choose browser" and choose Firefox
- Click "open com.org.mozilla.firefox"
- Click on the redd buttons when they appear (the first button is positioned so that the user clicks the "remember the decision" checkbox, the second to allow the permission)
- The site is now allowed to access the camera
Expected results:
Touches should be ignored during enter animations.
The source of this vulnerability is twofold: (1) Firefox does not wait for animations to be finished until it handles touches, and (2) Android allows long-running animations with low opacity.
To offer mitigations to protect users until (2) is fixed on the system level, we propose to also fix (1) and mitigate this issue at the browser level. Firefox can ignore all touch events until the onEnterAnimationComplete lifecycle method is called. This method is triggered once the enter animations are complete, thereby protecting against animation-based tapjacking.
| Reporter | ||
Comment 1•1 year ago
|
||
| Reporter | ||
Comment 2•1 year ago
|
||
Hi, we have also responsibly disclosed this issue with the Android Security Team (issue 376620895) as well as the following other affected browser vendors:
- Chrome (issue 1928334)
- Brave (issue 2813717)
- Edge (issue VULN-137894)
Best,
Philipp
Comment 3•1 year ago
|
||
Could you provide a link to the Chrome issue? That is too short a number for their current bug tracker, and the redirector for links to their old URLs says that's not a migrated issue. Or is it a number received from some other communication path with them? We know we won't be able to see their hidden bugs, but it's useful to have the reference in case we need to ask them about it.
Comment 4•1 year ago
|
||
Since this requires installing a malicious app perhaps sec-high is overstating it? But "sec-moderate" wouldn't convey the near-high severity of it.
| Reporter | ||
Comment 5•1 year ago
|
||
Hi, here is the correct Chrome issue: https://issues.chromium.org/issues/376491759
Updated•1 year ago
|
Comment 6•1 year ago
|
||
The severity field for this bug is set to S3. However, the bug is flagged with the sec-high keyword.
:boek, could you consider increasing the severity of this security bug?
For more information, please visit BugBot documentation.
| Assignee | ||
Updated•1 year ago
|
| Assignee | ||
Updated•1 year ago
|
Comment 7•1 year ago
|
||
Hey Jeff, this is a sec-high one - would you please add this to your queue?
| Reporter | ||
Comment 8•1 year ago
|
||
Dear Firefox Security Team,
I’d like to provide an update from our side. We are in the process of publishing our findings and evaluation of the Android Tapjacking vulnerability at the USENIX Security Symposium 2025. While the paper does not focus directly on Firefox, it discusses the broader impact of this vulnerability on the Web ecosystem as well, including Firefox.
The paper is currently under review. If accepted, it will be published in June 2025 and presented at the conference in August 2025.
Additionally, I'd like to give you an update from the Chrome side. Chrome has recently implemented mitigations for this issue by blocking touches until the onEnterAnimationComplete function is called (see https://chromium-review.googlesource.com/c/chromium/src/+/6244912 (public) and https://issuetracker.google.com/issues/376491759 (restricted)).
Best,
Philipp
| Assignee | ||
Comment 9•1 year ago
|
||
| Assignee | ||
Comment 10•11 months ago
|
||
[Security approval request comment]
How easily could an exploit be constructed based on the patch?
The patch clearly points to the potential of a tap jacking exploit.
Which branches (beta, release, and/or ESR) are affected by this flaw, and do the release status flags reflect this affected/unaffected state correctly?
All versions of Firefox for Android are affected.
Do you have backports for the affected branches? If not, how different, hard to create, and risky will they be?
No backports have been created. The patch should uplift cleanly. If fix is verified in Nightly risk should be low.
How likely is this patch to cause regressions; how much testing does it need?
Unlikely, but not impossible. Should continue to try to intentionally break it.
Is the patch ready to land after security approval is given?
Yes.
| Assignee | ||
Updated•11 months ago
|
Comment 11•11 months ago
|
||
Comment on attachment 9466902 [details]
Sec Approval Request
Approved to land and request uplift.
(It's generally easier to flag the actual patch for sec-approval rather than adding a new attachment, but no worries.)
| Assignee | ||
Comment 12•11 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D238342
Updated•11 months ago
|
Comment 13•11 months ago
|
||
beta Uplift Approval Request
- User impact if declined: Vulnerability will exist in 136
- Code covered by automated testing: yes
- Fix verified in Nightly: no
- Needs manual QE test: no
- Steps to reproduce for manual QE testing: steps can be found in the originating bug
- Risk associated with taking this patch: Low - Untested changes
- Explanation of risk level: The changes arent under unit test, but UI tests should catch any potential regressions
- String changes made/needed: none
- Is Android affected?: yes
Updated•11 months ago
|
Comment 14•11 months ago
|
||
:boek a reminder this needs to land in autoland today
Comment 15•11 months ago
|
||
Updated•11 months ago
|
Comment 16•11 months ago
|
||
Updated•11 months ago
|
Comment 17•11 months ago
|
||
| uplift | ||
Updated•11 months ago
|
Updated•11 months ago
|
Updated•11 months ago
|
Comment 18•11 months ago
|
||
Updated•11 months ago
|
Updated•7 months ago
|
Updated•7 months ago
|
Updated•6 months ago
|
Description
•