Skip to content
Draft
60 changes: 60 additions & 0 deletions best-practices/MASTG-BEST-0029.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
title: Preventing Overlay Attacks
alias: preventing-overlay-attacks
id: MASTG-BEST-0029
platform: android
knowledge: [MASTG-KNOW-0022]
---

Apps should protect sensitive user interactions from overlay attacks by implementing appropriate defensive mechanisms. Overlay attacks (including tapjacking) occur when malicious apps place deceptive UI elements over legitimate app interfaces to trick users into unintended actions.

## Recommendation

Implement touch filtering to prevent touch events when the app's UI is obscured by another app. Use one or more of the following mechanisms:

1. **Set the layout attribute `android:filterTouchesWhenObscured="true"`** for sensitive views such as login buttons, payment confirmations, or permission requests. This filters touch events when the view is obscured.

2. **Call `setFilterTouchesWhenObscured(true)`** programmatically on sensitive views to enable touch filtering at runtime.

3. **Call `setHideOverlayWindows(true)`** on the window (API level 31+) to hide all non-system overlay windows while the activity is in the foreground. This provides stronger protection by preventing overlays entirely rather than just filtering touch events.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot In the 1st and 2nd bullet points above you described one mechanism but applied in two different ways. The 3rd bullet points(this one) also has another way to apply the same technique by setting HIDE_OVERLAY_WINDOWS. I would even say this might be the most reliable way to stop overlays on supported API versions. I would add it too to the list.

Also, how about we sort this list by the most robust solutions. I believe HIDE_OVERLAY_WINDOWS / setHideOverlayWindows would be first one.

Then I would mention android:filterTouchesWhenObscured / setFilterTouchesWhenObscured.

Checking FLAG_WINDOW_IS_OBSCURED and FLAG_WINDOW_IS_PARTIALLY_OBSCURED might belong to a different category. They don't prevent touching UI if there is an overlay on the screen. Instead, they detect these overlays and allow to response accordingly. This might be worth mentioning.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot In the 1st and 2nd bullet points above you described one mechanism but applied in two different ways. The 3rd bullet points(this one) also has another way to apply the same technique by setting HIDE_OVERLAY_WINDOWS. I would even say this might be the most reliable way to stop overlays on supported API versions. I would add it too to the list.

Also, how about we sort this list by the most robust solutions. I believe HIDE_OVERLAY_WINDOWS / setHideOverlayWindows would be first one.

Then I would mention android:filterTouchesWhenObscured / setFilterTouchesWhenObscured.

Checking FLAG_WINDOW_IS_OBSCURED and FLAG_WINDOW_IS_PARTIALLY_OBSCURED might belong to a different category. They don't prevent touching UI if there is an overlay on the screen. Instead, they detect these overlays and allow to response accordingly. This might be worth mentioning.

Also, let's add Let's also add HIDE_OVERLAY_WINDOWS in knowledge/android/MASVS-PLATFORM/MASTG-KNOW-0022.md


4. **Override `onFilterTouchEventForSecurity`** for more granular control and to implement custom security policies based on your app's specific requirements.

5. **Check motion event flags** such as `FLAG_WINDOW_IS_OBSCURED` (API level 9+) or `FLAG_WINDOW_IS_PARTIALLY_OBSCURED` (API level 29+) in touch event handlers to detect obscured windows and respond appropriately.

Apply these protections selectively to security-sensitive UI elements where user confirmation is critical, such as:

- Login and authentication screens
- Permission request dialogs
- Payment confirmation buttons
- Sensitive data entry fields
- Security settings changes

## Rationale

Without overlay protection, malicious apps can:

- Capture user credentials by overlaying fake login screens
- Trick users into granting dangerous permissions
- Intercept sensitive data entry
- Perform unauthorized actions by obscuring the true nature of UI elements

Touch filtering mechanisms help ensure that user interactions occur with the intended UI elements and not with overlays placed by malicious apps.

## Caveats and Considerations

- Touch filtering is not a complete solution on older Android versions that have system-level vulnerabilities. Apps should target modern API levels when possible.
- Some attacks, particularly those exploiting system-level vulnerabilities (for example, Toast Overlay on Android versions before 8.0), cannot be fully mitigated at the app level.
- Applying touch filtering too broadly may impact legitimate use cases where overlays are expected (for example, system dialogs, accessibility features).
- Users can still be tricked through social engineering even with touch filtering enabled. Apps should combine these protections with user education and clear UI indicators.
- For maximum protection, apps targeting older API levels should consider upgrading their `targetSdkVersion` to benefit from platform-level protections introduced in newer Android versions.

## References

- Android Developer Documentation: [Tapjacking](https://developer.android.com/privacy-and-security/risks/tapjacking)
- Android Developer Documentation: [View Security](https://developer.android.com/reference/android/view/View#security)
- Android Developer Documentation: [setFilterTouchesWhenObscured](https://developer.android.com/reference/android/view/View#setFilterTouchesWhenObscured(boolean))
- Android Developer Documentation: [setHideOverlayWindows](https://developer.android.com/reference/android/view/Window#setHideOverlayWindows(boolean))
- Android Developer Documentation: [onFilterTouchEventForSecurity](https://developer.android.com/reference/android/view/View#onFilterTouchEventForSecurity(android.view.MotionEvent))
- Android Developer Documentation: [FLAG_WINDOW_IS_OBSCURED](https://developer.android.com/reference/android/view/MotionEvent#FLAG_WINDOW_IS_OBSCURED)
- Android Developer Documentation: [FLAG_WINDOW_IS_PARTIALLY_OBSCURED](https://developer.android.com/reference/android/view/MotionEvent#FLAG_WINDOW_IS_PARTIALLY_OBSCURED)
52 changes: 52 additions & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0x83/MASTG-DEMO-0x83.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
platform: android
title: Overlay Attack Protection Implementation
id: MASTG-DEMO-0x83
code: [kotlin, java]
test: MASTG-TEST-0x35
tools: [semgrep]
---

### Sample

This sample demonstrates different approaches to protecting against overlay attacks in Android apps. It includes both a vulnerable implementation (without protection) and secure implementations using various overlay protection mechanisms.

{{ MastgTest.kt # MastgTest_reversed.java }}

The code shows three buttons:

1. **Vulnerable button** - A Compose button without any overlay protection, making it susceptible to tapjacking attacks
2. **Protected button** - A traditional Android View Button with `filterTouchesWhenObscured = true` to block touches when the window is obscured
3. **Custom protected button** - A button with a custom implementation that overrides `onFilterTouchEventForSecurity` to manually check for the `FLAG_WINDOW_IS_OBSCURED` flag

### Steps

Let's run our semgrep rule against the decompiled code to detect overlay protection mechanisms.

{{ ../../../../rules/mastg-android-overlay-protection.yml }}

{{ run.sh }}

### Observation

The semgrep rule detected three instances of overlay protection mechanisms in the code:

{{ output.txt }}

The output shows:

1. Line 59: `setFilterTouchesWhenObscured(true)` - enabling touch filtering on the protected button
2. Lines 73-79: `onFilterTouchEventForSecurity` - custom override implementation
3. Line 74: Check for `FLAG_WINDOW_IS_OBSCURED` flag - detecting when the window is obscured

### Evaluation

The test partially passes and partially fails:

**FAIL:** The first button (lines 38-48 in the Kotlin code, not shown in the output) does not implement any overlay protection. This button performs a sensitive action (payment confirmation) and should be protected against overlay attacks.

**PASS:** The second button (line 59 in the decompiled output) properly implements overlay protection using `setFilterTouchesWhenObscured(true)`, which will filter touch events when the view is obscured by another window.

**PASS:** The third button (lines 73-79 in the decompiled output) implements custom overlay protection by overriding `onFilterTouchEventForSecurity` and manually checking the `FLAG_WINDOW_IS_OBSCURED` flag. This provides fine-grained control over how the app responds to overlay attempts.

In a real-world assessment, the vulnerable button should be flagged as a finding. Sensitive UI elements such as payment confirmations, permission grants, or authentication buttons should implement overlay protection using one of the demonstrated mechanisms.
58 changes: 58 additions & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0x83/MastgTest.kt
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Demo is missing:

class MastgTest (private val context: Context){

    fun shouldRunInMainThread(): Boolean = true

    fun mastgTest(): String {

Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.owasp.mastestapp

import android.content.Context
import android.view.MotionEvent
import android.widget.Button
import android.widget.LinearLayout

// SUMMARY: This sample demonstrates different approaches to handling overlay attacks in Android apps,
// showing both vulnerable patterns and proper protections using filterTouchesWhenObscured.

class MastgTest (private val context: Context){

fun mastgTest(): String {
val layout = LinearLayout(context)
layout.orientation = LinearLayout.VERTICAL

// FAIL: [MASTG-TEST-0x35] Sensitive button without overlay protection
val vulnerableButton = Button(context).apply {
text = "Vulnerable: Confirm Payment"
setOnClickListener {
// Sensitive action: confirming a payment
}
}
layout.addView(vulnerableButton)

// PASS: [MASTG-TEST-0x35] Button with overlay protection using filterTouchesWhenObscured
val protectedButton = Button(context).apply {
text = "Protected: Confirm Payment"
filterTouchesWhenObscured = true
setOnClickListener {
// Sensitive action protected from overlay attacks
}
}
layout.addView(protectedButton)

// PASS: [MASTG-TEST-0x35] Custom view with manual obscured check
val customProtectedButton = object : Button(context) {
override fun onFilterTouchEventForSecurity(event: MotionEvent): Boolean {
if ((event.flags and MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) {
// Window is obscured, filter the touch event
return false
}
return super.onFilterTouchEventForSecurity(event)
}
}.apply {
text = "Custom Protection: Grant Permission"
setOnClickListener {
// Sensitive permission grant protected by custom implementation
}
}
layout.addView(customProtectedButton)

return "Created buttons with various overlay protections:\n" +
"1. Vulnerable button (no protection)\n" +
"2. Protected button (filterTouchesWhenObscured)\n" +
"3. Custom protected button (onFilterTouchEventForSecurity)"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.owasp.mastestapp;

import android.content.Context;
import android.view.MotionEvent;
import android.widget.Button;
import android.widget.LinearLayout;
import kotlin.jvm.internal.Intrinsics;

public final class MastgTest {
private final Context context;

public MastgTest(Context context) {
Intrinsics.checkNotNullParameter(context, "context");
this.context = context;
}

public final String mastgTest() {
LinearLayout layout = new LinearLayout(this.context);
layout.setOrientation(1);

// FAIL: [MASTG-TEST-0x35] Sensitive button without overlay protection
Button vulnerableButton = new Button(this.context);
vulnerableButton.setText("Vulnerable: Confirm Payment");
vulnerableButton.setOnClickListener(view -> {
// Sensitive action: confirming a payment
});
layout.addView(vulnerableButton);

// PASS: [MASTG-TEST-0x35] Button with overlay protection using filterTouchesWhenObscured
Button protectedButton = new Button(this.context);
protectedButton.setText("Protected: Confirm Payment");
protectedButton.setFilterTouchesWhenObscured(true);
protectedButton.setOnClickListener(view -> {
// Sensitive action protected from overlay attacks
});
layout.addView(protectedButton);

// PASS: [MASTG-TEST-0x35] Custom view with manual obscured check
Button customProtectedButton = new Button(this.context) {
public boolean onFilterTouchEventForSecurity(MotionEvent event) {
if ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) {
// Window is obscured, filter the touch event
return false;
}
return super.onFilterTouchEventForSecurity(event);
}
};
customProtectedButton.setText("Custom Protection: Grant Permission");
customProtectedButton.setOnClickListener(view -> {
// Sensitive permission grant protected by custom implementation
});
layout.addView(customProtectedButton);

return "Created buttons with various overlay protections:\n" +
"1. Vulnerable button (no protection)\n" +
"2. Protected button (filterTouchesWhenObscured)\n" +
"3. Custom protected button (onFilterTouchEventForSecurity)";
}
}
29 changes: 29 additions & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0x83/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@


┌─────────────────┐
│ 4 Code Findings │
└─────────────────┘

MastgTest_reversed.java
❱ rules.mastg-android-overlay-protection-setfiltertoucheswhenobscured
[MASVS-PLATFORM-3] setFilterTouchesWhenObscured is used to protect against overlay attacks

59┆ button.setFilterTouchesWhenObscured(true);

❱ rules.mastg-android-overlay-protection-onfiltertoucheventforsecurity
[MASVS-PLATFORM-3] onFilterTouchEventForSecurity is overridden for custom overlay protection

73┆ public boolean onFilterTouchEventForSecurity(MotionEvent event) {
74┆ if ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) {
75┆ Toast.makeText(this.getContext(), "Touch blocked - window obscured", 0).show();
76┆ return false;
77┆ }
78┆ return super.onFilterTouchEventForSecurity(event);
79┆ }

❱ rules.mastg-android-overlay-protection-flag-window-is-obscured
[MASVS-PLATFORM-3] FLAG_WINDOW_IS_OBSCURED is checked to detect overlay attacks

74┆ if ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) {
⋮┆----------------------------------------
74┆ if ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) {
4 changes: 4 additions & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0x83/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

# Run semgrep to detect overlay protection mechanisms
NO_COLOR=true semgrep -c ../../../../rules/mastg-android-overlay-protection.yml ./MastgTest_reversed.java --text -o output.txt
22 changes: 15 additions & 7 deletions knowledge/android/MASVS-PLATFORM/MASTG-KNOW-0022.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,22 @@ platform: android
title: Overlay Attacks
---

Screen overlay attacks occur when a malicious application manages to put itself on top of another application which remains working normally as if it were on the foreground. The malicious app might create UI elements mimicking the look and feel and the original app or even the Android system UI. The intention is typically to make users believe that they keep interacting with the legitimate app and then try to elevate privileges (e.g by getting some permissions granted), stealthy phishing, capture user taps and keystrokes etc.
Screen overlay attacks occur when a malicious application places itself on top of another application which continues to function normally in the foreground. The malicious app can create UI elements that mimic the appearance of the legitimate app or the Android system UI. The goal is typically to deceive users into believing they are interacting with the legitimate app to elevate privileges (for example, by getting permissions granted), conduct phishing, or capture user taps and keystrokes.

There are several attacks affecting different Android versions including:
There are several types of overlay attacks affecting different Android versions:

- [**Tapjacking**](https://medium.com/devknoxio/what-is-tapjacking-in-android-and-how-to-prevent-it-50140e57bf44 "What is Tapjacking in Android and How to Prevent It") (Android 6.0 (API level 23) and lower) abuses the screen overlay feature of Android listening for taps and intercepting any information being passed to the underlying activity.
- [**Cloak & Dagger**](https://cloak-and-dagger.org/ "Cloak & Dagger") attacks affect apps targeting Android 5.0 (API level 21) to Android 7.1 (API level 25). They abuse one or both of the `SYSTEM_ALERT_WINDOW` ("draw on top") and `BIND_ACCESSIBILITY_SERVICE` ("a11y") permissions that, in case the app is installed from the Play Store, the users do not need to explicitly grant and for which they are not even notified.
- [**Toast Overlay**](https://unit42.paloaltonetworks.com/unit42-android-toast-overlay-attack-cloak-and-dagger-with-no-permissions/ "Android Toast Overlay Attack: Cloak and Dagger with No Permissions") is quite similar to Cloak & Dagger but do not require specific Android permissions to be granted by users. It was closed with CVE-2017-0752 on Android 8.0 (API level 26).
- [**Tapjacking**](https://developer.android.com/privacy-and-security/risks/tapjacking) (historically affecting Android 6.0 (API level 23) and lower) exploits the screen overlay feature by listening for taps and intercepting information passed to underlying activities.
- [**Cloak & Dagger**](https://cloak-and-dagger.org/) attacks affected apps targeting Android 5.0 (API level 21) to Android 7.1 (API level 25). They abused the `SYSTEM_ALERT_WINDOW` ("draw on top") and/or `BIND_ACCESSIBILITY_SERVICE` ("a11y") permissions. When apps were installed from the Play Store, users did not need to explicitly grant these permissions and were not even notified.
- [**Toast Overlay**](https://unit42.paloaltonetworks.com/unit42-android-toast-overlay-attack-cloak-and-dagger-with-no-permissions/) was similar to Cloak & Dagger but did not require specific Android permissions from users. It was patched with CVE-2017-0752 in Android 8.0 (API level 26).

Usually, this kind of attacks are inherent to an Android system version having certain vulnerabilities or design issues. This makes them challenging and often virtually impossible to prevent unless the app is upgraded targeting a safe Android version (API level).
Android provides several defensive mechanisms that apps can use to protect against overlay attacks:

Over the years many known malware like MazorBot, BankBot or MysteryBot have been abusing the screen overlay feature of Android to target business critical applications, namely in the banking sector. This [blog](https://www.infosecurity-magazine.com/opinions/overlay-attacks-safeguard-mobile/ "Dealing with Overlay Attacks: Adopting Built-in Security to Safeguard Mobile Experience") discusses more about this type of malware.
- [`onFilterTouchEventForSecurity`](https://developer.android.com/reference/android/view/View#onFilterTouchEventForSecurity(android.view.MotionEvent)): Override this method for fine-grained control to implement custom security policies for views.
- [`android:filterTouchesWhenObscured`](https://developer.android.com/reference/android/view/View#attr_android:filterTouchesWhenObscured): Set this layout attribute to `true` or call [`setFilterTouchesWhenObscured`](https://developer.android.com/reference/android/view/View#setFilterTouchesWhenObscured(boolean)) to filter touch events when the view is obscured by another visible window.
- [`setHideOverlayWindows`](https://developer.android.com/reference/android/view/Window#setHideOverlayWindows(boolean)) (since API level 31): Call this method on the window to hide all non-system overlay windows while the activity is in the foreground. This provides a stronger protection by preventing overlays entirely rather than just filtering touch events.
- [`FLAG_WINDOW_IS_OBSCURED`](https://developer.android.com/reference/android/view/MotionEvent#FLAG_WINDOW_IS_OBSCURED) (since API level 9): Check this flag to detect if the window is obscured.
- [`FLAG_WINDOW_IS_PARTIALLY_OBSCURED`](https://developer.android.com/reference/android/view/MotionEvent#FLAG_WINDOW_IS_PARTIALLY_OBSCURED) (since API level 29): Check this flag to detect if the window is partially obscured.

Many overlay attacks are inherent to specific Android system versions due to vulnerabilities or design issues. Modern Android versions have introduced system-level protections that make these attacks more difficult, but apps targeting older API levels may remain vulnerable.

Over the years, malware such as MazorBot, BankBot, and MysteryBot have exploited screen overlays to target business-critical applications, particularly in the banking sector.
Loading
Loading