Skip to content
Open
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bb3bb4d
Enhance documentation on screenshot handling in Android, detailing sy…
cpholguera Aug 31, 2025
fff4ec9
Revise guidelines on preventing sensitive data capture, detailing ris…
cpholguera Aug 31, 2025
a9e5cbc
Add additional rules for FLAG_SECURE handling and recents screenshot …
cpholguera Aug 31, 2025
870fca7
Add guidelines for identifying sensitive screens during testing
cpholguera Aug 31, 2025
875244f
Update FLAG_SECURE usage examples and documentation in Android MASTG-…
cpholguera Sep 3, 2025
1a66957
Add new MASTG-DEMO-0062 for setRecentsScreenshotEnabled in Android 14+
cpholguera Sep 3, 2025
6604db3
Add new MASTG-DEMO-0063 for Jetpack Compose Dialogs
cpholguera Sep 3, 2025
fa08647
Remove redundant rules for recents screenshot enabled/disabled in sen…
cpholguera Sep 3, 2025
771a7fc
Enhance documentation for screen capture prevention APIs, including d…
cpholguera Sep 3, 2025
81c6310
rm extra ref to file
cpholguera Sep 6, 2025
c58f7b3
Merge branch 'master' of https://github.com/OWASP/owasp-mastg into mo…
cpholguera Sep 6, 2025
7af35bd
refine documentation on FLAG_SECURE usage for Android UI components
cpholguera Sep 6, 2025
a6bbca3
refine wording and clarity in MASTG-TEST-0291.md regarding FLAG_SECUR…
cpholguera Sep 6, 2025
e4d8754
fix regex
cpholguera Sep 6, 2025
1c3369a
Split best practices for preventing screenshots in Android apps.
cpholguera Sep 6, 2025
4a483b4
Split tests for preventing screenshots in Android apps.
cpholguera Sep 6, 2025
3250c83
Fix test refs
cpholguera Sep 6, 2025
de7c3a0
add refs
cpholguera Sep 6, 2025
3111eda
link best to knowledge
cpholguera Sep 6, 2025
3c6eb43
Clarify wording in MASTG-TEST-0291.md for better readability
cpholguera Sep 6, 2025
13975cb
Add best practice for non-caching input types in sensitive fields
cpholguera Sep 6, 2025
1d946d8
Update MASTG-BEST-0018.md to clarify usage of SecureFlagPolicy.Secure…
cpholguera Sep 6, 2025
01e9d69
Add reference to overlay attack warnings and improve wording in MASTG…
cpholguera Sep 7, 2025
83c1346
Correct MASTG-KNOW-0053 location
cpholguera Sep 7, 2025
8d83288
Update MASTG-KNOW-0022.md to correct Tapjacking reference and add bes…
cpholguera Sep 7, 2025
532d4a1
Update best practices and knowledge documents for screenshot preventi…
cpholguera Sep 14, 2025
07a89e6
Add MASTG-KNOW-0107.md for screenshots and screen recording detection…
cpholguera Sep 14, 2025
5c8a99e
fix indentation
cpholguera Sep 19, 2025
d9ff8d4
Merge branch 'master' into more-android-screenshots-testing
cpholguera Sep 19, 2025
a95e414
Apply suggestions from code review
cpholguera Sep 19, 2025
b18f69c
Merge branch 'master' of https://github.com/OWASP/owasp-mastg into mo…
cpholguera Sep 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 8 additions & 13 deletions best-practices/MASTG-BEST-0014.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,16 @@ title: Preventing Screenshots and Screen Recording
alias: preventing-screenshots-and-screen-recording
id: MASTG-BEST-0014
platform: android
parent: None
---

Ensure the app hides sensitive content, such as card numbers and passcodes, from screenshots, screen recording, nonsecure displays, task switcher thumbnails, and remote screen sharing. Malware may capture screen output and extract confidential information. Protect on screen keyboards or custom keypad views as they may leak keystrokes from passcode fields. Screenshots can be saved in locations accessible to other apps or a local attacker.
Apps should prevent sensitive data from being captured from the UI, leaving the control of the user, and potentially leaking. This includes the following considerations:

Setting [`FLAG_SECURE`](https://developer.android.com/security/fraud-prevention/activities#flag_secure) on the window prevents screenshots (or appear black), blocks screen recording, and hides content on nonsecure displays and in the system task switcher.
- **System-generated snapshots** are sandboxed, but may still be accessible on rooted or compromised devices or through forensic acquisition.
- **User-initiated screenshots** are accessible to the user and to any app with storage or media access. They may also be automatically synced to cloud services such as Google Photos.
- **Screen recordings** can capture all visual content, including transient data such as passcodes or one-time codes, and may be stored or shared without the user's awareness.
- **Non-secure displays and remote screen sharing** can expose sensitive information to external monitors, casting devices, or remote control software.

<div style="display:flex; flex-wrap:wrap; gap:16px; align-items:flex-start; margin:16px 0;">
<figure style="flex:1 1 220px; margin:0; text-align:center;">
<img src="Images/Chapters/0x05d/task-switcher-without-flag-secure.png" width="200" alt="Task switcher without FLAG_SECURE">
<figcaption>Without <code>FLAG_SECURE</code></figcaption>
</figure>
<figure style="flex:1 1 220px; margin:0; text-align:center;">
<img src="Images/Chapters/0x05d/task-switcher-with-flag-secure.png" width="200" alt="Task switcher with FLAG_SECURE">
<figcaption>With <code>FLAG_SECURE</code></figcaption>
</figure>
</div>
Depending on the threat model of the app, one or more protections may be required. For example, on-screen keyboards or custom keypad views should be secured to prevent keystroke leakage from passcode fields. A banking app should ensure that account balances or transaction details are never visible in captured images, unless the user explicitly chooses to allow screenshots.

You can follow the official documentation to implement `FLAG_SECURE` in your app, see ["Secure sensitive activities"](https://developer.android.com/security/fraud-prevention/activities).
**Consider adding an in-app setting** to enable or disable this behavior, giving users control without compromising security by default.
28 changes: 28 additions & 0 deletions best-practices/MASTG-BEST-0015.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
title: Use `setRecentsScreenshotEnabled` to Prevent Screenshots When Backgrounded
alias: preventing-screenshots-when-backgrounded
id: MASTG-BEST-0015
parent: MASTG-BEST-0014
knowledge: [MASTG-KNOW-0053]
platform: android
component: android.app.Activity
available_since: 33
---

Preventing screenshots when an app is backgrounded helps protect sensitive data from being exposed in system-generated snapshots used by the [Recents screen](https://developer.android.com/guide/components/activities/recents). This is especially important for apps that handle sensitive information, such as banking, healthcare, or enterprise apps. For example, a banking app should ensure that account balances, transaction details, or card numbers never appear in the Recents screen, unless the user explicitly chooses to allow it using an in-app setting.

Even though **system-generated snapshots** are sandboxed, they may still be accessible on rooted or compromised devices or through forensic acquisition.

Using `FLAG_SECURE` consistently on all UI components as indicated in @MASTG-BEST-0014 helps prevent system-generated snapshots from showing sensitive data in the [Recents screen](https://developer.android.com/guide/components/activities/recents) when the app is backgrounded. However, getting it right can be challenging, as there's no global setting to enforce it across the entire app.

Starting with Android 13 (API level 33), you can use [`setRecentsScreenshotEnabled(false)`](https://developer.android.com/reference/android/app/Activity#setRecentsScreenshotEnabled(boolean)) to ensure that the app's content is not shown in the Recents screen when backgrounded.

- The snapshots saved to `/data/system_ce/<user_id>/snapshots` will be blank/obscured.
- The previews in the Recents screen will be blank after the user switches away from the app completely, similar to the behavior of `FLAG_SECURE`.

!!! warning "What `setRecentsScreenshotEnabled` Does Not"

Setting `setRecentsScreenshotEnabled(false)` does not prevent user-initiated screenshots or screen recordings.

- Users can take screenshots using the hardware shortcut and the content will appear in those screenshots.
- Tapping "Screenshot" in the Recents screen will not work (the system may show a policy message depending on device/ROM).
43 changes: 43 additions & 0 deletions best-practices/MASTG-BEST-0016.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
title: Use `SECURE_FLAG` to Prevent Screenshots and Screen Recording
alias: use-secure-flag-to-prevent-screenshots-and-screen-recording
id: MASTG-BEST-0016
parent: MASTG-BEST-0014
knowledge: [MASTG-KNOW-0053, MASTG-KNOW-0105, MASTG-KNOW-0106]
platform: android
component: android.view.Window
available_since: 1
refs:
- https://developer.android.com/security/fraud-prevention/activities#flag_secure
- https://support.google.com/googleplay/android-developer/answer/16273414
- https://support.google.com/googleplay/android-developer/answer/14638385
- https://proandroiddev.com/multitasking-intrusion-and-preventing-screenshots-in-android-app-15bd8757c24d
---

Setting [`FLAG_SECURE`](https://developer.android.com/reference/android/view/WindowManager.LayoutParams#FLAG_SECURE) on a window prevents screenshots (or makes them appear black), blocks screen recording, and hides content on non-secure displays and ensures that the app's content is not shown in the [Recents screen](https://developer.android.com/guide/components/activities/recents) when backgrounded.

<div style="display:flex; flex-wrap:wrap; gap:16px; align-items:flex-start; margin:16px 0;">
<figure style="flex:1 1 220px; margin:0; text-align:center;">
<img src="Images/Chapters/0x05d/task-switcher-without-flag-secure.png" width="200" alt="Task switcher without FLAG_SECURE">
<figcaption>Without <code>FLAG_SECURE</code></figcaption>
</figure>
<figure style="flex:1 1 220px; margin:0; text-align:center;">
<img src="Images/Chapters/0x05d/task-switcher-with-flag-secure.png" width="200" alt="Task switcher with FLAG_SECURE">
<figcaption>With <code>FLAG_SECURE</code></figcaption>
</figure>
</div>

The flag is applied with [`addFlags()`](https://developer.android.com/reference/android/view/Window#addFlags(int)) or [`setFlags()`](https://developer.android.com/reference/android/view/Window#setFlags(int,int)). Common best practices include:

- This flag cannot be applied globally. Apply the flag to all windows that can show sensitive data, including `Activity`, `Dialog`, `DialogFragment`, `AlertDialog`, or any custom window added via `WindowManager`. Sometimes apps **use a base UI class and use inheritance** to ensure all sensitive screens have it set.
- Set the flag as early as possible in the lifecycle, before sensitive content is rendered. For example, setting it in `onCreate()` is better than `onResume()`, and trying to add the flag in `onPause()` is not effective, as the preview is created before this method is called.
- Be careful with fragments and their lifecycle, as they can be added or removed dynamically.
- Avoid clearing the flag during transitions (e.g., using [`clearFlags()`](https://developer.android.com/reference/android/view/Window#clearFlags(int)) or `setFlags()` without reapplying), as sensitive previews for the Recents screen can be captured before callbacks like `onPause()`.

Note that you cannot set `FLAG_SECURE` directly on components that do not expose `getWindow()`, such as `android.widget.PopupWindow` or `android.widget.Toast`.
- `android.view.View` and subclasses like `android.widget.TextView`, `android.widget.EditText`, `android.webkit.WebView`, `android.view.TextureView`, etc. don't support `FLAG_SECURE`. You must secure their containing Window instead. Alternatively, you can mask passwords and other sensitive by following the recommendations in @MASTG-BEST-0019.

Check failure on line 38 in best-practices/MASTG-BEST-0016.md

View workflow job for this annotation

GitHub Actions / markdown-lint-check

Lists should be surrounded by blank lines

best-practices/MASTG-BEST-0016.md:38 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "- `android.view.View` and subc..."] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md032.md

For more information, refer to the official documentation.

**Important:** Google warns that this approach isn't reliable for protecting against overlay attacks (@MASTG-KNOW-0022). See ["Secure sensitive activities - Best practices"](https://developer.android.com/security/fraud-prevention/activities#best-practices).

12 changes: 12 additions & 0 deletions best-practices/MASTG-BEST-0017.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: Use `setSecure` to Prevent Screenshots in SurfaceViews
alias: preventing-screenshots-and-screen-recording
id: MASTG-BEST-0017
parent: MASTG-BEST-0014
knowledge: [MASTG-KNOW-0053, MASTG-KNOW-0105, MASTG-KNOW-0106]
platform: android
component: android.view.SurfaceView
available_since: 17
---

`SurfaceView` creates a separate surface that is not protected by `FLAG_SECURE` even if the containing window has it set. To protect content in a `SurfaceView`, use [`setSecure(true)`](https://developer.android.com/reference/android/view/SurfaceView#setSecure(boolean)) before the surface view's containing window is attached to the window manager.
16 changes: 16 additions & 0 deletions best-practices/MASTG-BEST-0018.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: Use `SecureFlagPolicy.SecureOn` to Prevent Screenshots in Compose Components
alias: use-secureon-in-compose-components
id: MASTG-BEST-0018
parent: MASTG-BEST-0014
knowledge: [MASTG-KNOW-0053, MASTG-KNOW-0105, MASTG-KNOW-0106]
platform: android
component: androidx.compose.ui:ui
available_since: 1.0.0
---

Use [`SecureFlagPolicy.SecureOn`](https://developer.android.com/reference/kotlin/androidx/compose/ui/window/SecureFlagPolicy#SecureOn) for Jetpack Compose dialogs and popups that display sensitive information (via [`DialogProperties.securePolicy`](https://developer.android.com/reference/kotlin/androidx/compose/ui/window/DialogProperties#securePolicy()) or [`PopupProperties.securePolicy`](https://developer.android.com/reference/kotlin/androidx/compose/ui/window/PopupProperties#securePolicy()) respectively). This applies the underlying Window's [`FLAG_SECURE`](https://developer.android.com/reference/android/view/WindowManager.LayoutParams#FLAG_SECURE), which blocks screenshots, screen recordings, display on insecure devices and prevents previews in the Recents screen.

Define the policy at creation time and avoid toggling it while visible. If the dialog or popup should follow the host window's state, use [`SecureFlagPolicy.Inherit`](https://developer.android.com/reference/kotlin/androidx/compose/ui/window/SecureFlagPolicy#Inherit). Avoid [`SecureFlagPolicy.SecureOff`](https://developer.android.com/reference/kotlin/androidx/compose/ui/window/SecureFlagPolicy#SecureOff) for sensitive content.

Be aware that the use of this API may interfere with workflows like screenshots or screen sharing. If your threat model allows, consider offering an explicit user option to disable secure mode for non-sensitive scenarios, but default to secure behavior.
36 changes: 36 additions & 0 deletions best-practices/MASTG-BEST-0019.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: Use Non-Caching Input Types for Sensitive Fields
alias: use-non-caching-input-types
id: MASTG-BEST-0019
knowledge: [MASTG-KNOW-0055]
platform: android
refs:
- https://developer.android.com/reference/android/text/InputType
- https://developer.android.com/reference/kotlin/androidx/compose/foundation/text/KeyboardOptions
---

Use non-caching input types for any UI element that handles sensitive information (passwords, passphrases, PINs, recovery phrases, payment data). Password-style input types instruct the on-screen keyboard not to cache or learn from the entered text and disable suggestions and auto-correction. Password variations disable dictionary learning and suggestions in most IMEs and prevent caching of entered secrets.

Combine this practice with broader data leakage controls e.g., @MASTG-BEST-0014 when appropriate.

Recommendations:

- XML layouts (EditText)
- Passwords: `android:inputType="textPassword"`
- Numeric PINs: `android:inputType="numberPassword"`
- Avoid: `textVisiblePassword` and plain `text`/`number` without password variation.

- Programmatic (View-based UI)
- Passwords: `setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD)`
- Numeric PINs: `setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD)`
- Optionally disable suggestions for non-password sensitive fields: add `InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS`.

- Jetpack Compose
- Passwords: `KeyboardOptions(keyboardType = KeyboardType.Password, autoCorrect = false)`
- Numeric PINs: `KeyboardOptions(keyboardType = KeyboardType.NumberPassword, autoCorrect = false)`
- Also set a visual transformation where appropriate (e.g., `PasswordVisualTransformation()`).

- For sensitive but non-password inputs (e.g., security answers), prefer password variations or at minimum disable suggestions (`TYPE_TEXT_FLAG_NO_SUGGESTIONS`, `autoCorrect = false`).

- Overriding a non-caching type later in code with a generic class type (e.g., setting `TYPE_NUMBER_VARIATION_PASSWORD` and then setting `TYPE_CLASS_NUMBER`).

20 changes: 15 additions & 5 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0061/MASTG-DEMO-0061.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,41 @@
---
platform: android
title: Uses of FLAG_SECURE with semgrep
title: Setting and Clearing FLAG_SECURE in an Activity and Dialog with semgrep
id: MASTG-DEMO-0061
code: [kotlin]
test: MASTG-TEST-0291
---

### Sample

The sample uses the `addFlags` method to set the `FLAG_SECURE` window flag on an activity that displays sensitive data.
The sample demonstrates multiple ways of preventing screenshots of sensitive content in two Android components: an Activity and a standard Dialog. It also demonstrates incorrect ways of removing the screenshot prevention.

{{ MastgTest.kt # MastgTest_reversed.java }}

### Steps

Let's run our @MASTG-TOOL-0110 rule against the reversed java code.
Let's run our @MASTG-TOOL-0110 rule against the reversed Java code.

{{ ../../../../rules/mastg-android-sensitive-data-in-screenshot.yml }}

{{ run.sh }}

### Observation

The rule has identified one location in the code file where the app has set the `FLAG_SECURE` window flag using the `addFlags` method.
The rule has identified several locations in the code file where the app sets or clears the `FLAG_SECURE` window flag.

{{ output.txt }}

### Evaluation

This test passes because the app used the `addFlags` method to set the `FLAG_SECURE` window flag on an activity that displays sensitive data.
The test fails because even though the app demonstrates correct protection patterns by setting `FLAG_SECURE` for an Activity and a dialog, it subsequently removes protection by clearing/overwriting `FLAG_SECURE` on both the Activity and the dialog.

We can see this in `MastgTest_reversed.java`:

- For the activity:
- it adds the `FLAG_SECURE` flag via `getWindow().addFlags(8192)` (line 35)
- sets it again with `getWindow().setFlags(8192, 8192)` (line 36)
- and then immediately clears it with `getWindow().setFlags(0, 8192)` (line 37)
- For the dialog:
- it sets `window.setFlags(8192, 8192)` (line 42)
- and then calls `window2.clearFlags(8192)` (line 46)
19 changes: 18 additions & 1 deletion demos/android/MASVS-PLATFORM/MASTG-DEMO-0061/MastgTest.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.owasp.mastestapp

import android.app.Activity
import android.app.AlertDialog
import android.content.Context
import android.view.WindowManager.LayoutParams

Expand All @@ -12,9 +13,25 @@ class MastgTest (private val context: Context){
if (context is Activity) {
context.window.addFlags(LayoutParams.FLAG_SECURE)

return "SUCCESS!!\n\nThe FLAG_SECURE has been set"
// Activity window
context.window.setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE)
context.window.setFlags(0, LayoutParams.FLAG_SECURE)

// Standard dialog
val dialog = AlertDialog.Builder(context)
.setTitle("Secure dialog")
.setMessage("FLAG_SECURE is applied to this dialog.")
.setPositiveButton("OK", null)
.create()
dialog.show()
dialog.window?.setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE)
dialog.window?.clearFlags(LayoutParams.FLAG_SECURE)


return "SUCCESS!!\n\nFLAG_SECURE has been set for the Activity window"
} else {
return "ERROR: Context is not an Activity"
}

}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.owasp.mastestapp;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.Window;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;

Expand Down Expand Up @@ -30,7 +33,20 @@ public final void setShouldRunInMainThread(boolean z) {
public final String mastgTest() {
if (this.context instanceof Activity) {
((Activity) this.context).getWindow().addFlags(8192);
return "SUCCESS!!\n\nThe FLAG_SECURE has been set";
((Activity) this.context).getWindow().setFlags(8192, 8192);
((Activity) this.context).getWindow().setFlags(0, 8192);
AlertDialog dialog = new AlertDialog.Builder(this.context).setTitle("Secure dialog").setMessage("FLAG_SECURE is applied to this dialog.").setPositiveButton("OK", (DialogInterface.OnClickListener) null).create();
dialog.show();
Window window = dialog.getWindow();
if (window != null) {
window.setFlags(8192, 8192);
}
Window window2 = dialog.getWindow();
if (window2 != null) {
window2.clearFlags(8192);
return "SUCCESS!!\n\nFLAG_SECURE has been set for the Activity window";
}
return "SUCCESS!!\n\nFLAG_SECURE has been set for the Activity window";
}
return "ERROR: Context is not an Activity";
}
Expand Down
29 changes: 23 additions & 6 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0061/output.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@


┌────────────────┐
1 Code Finding
└────────────────┘
┌────────────────
5 Code Findings
└────────────────

MastgTest_reversed.java
❱ rules.mastg-android-flag-secure-enable-flags
[MASVS-PLATFORM] Make sure you use this flag for all screens with sensitive data

32┆ ((Activity) this.context).getWindow().addFlags(8192);
35┆ ((Activity) this.context).getWindow().addFlags(8192);
⋮┆----------------------------------------
36┆ ((Activity) this.context).getWindow().setFlags(8192, 8192);

❯❱ rules.mastg-android-flag-secure-clear-flags
[MASVS-PLATFORM] Window clears or overwrites FLAG_SECURE.

37┆ ((Activity) this.context).getWindow().setFlags(0, 8192);

❱ rules.mastg-android-flag-secure-enable-flags
[MASVS-PLATFORM] Make sure you use this flag for all screens with sensitive data

42┆ window.setFlags(8192, 8192);

❯❱ rules.mastg-android-flag-secure-clear-flags
[MASVS-PLATFORM] Window clears or overwrites FLAG_SECURE.

46┆ window2.clearFlags(8192);

Loading
Loading