Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
110 changes: 110 additions & 0 deletions best-practices/MASTG-BEST-0029.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
title: Marking UI Views as Containing Sensitive Data
alias: marking-ui-views-sensitive-data
id: MASTG-BEST-0029
platform: android
knowledge: [MASTG-KNOW-0108]
available_since: 35
---

## Overview

Starting with Android 16 (API level 35), developers should mark sensitive UI views using the [`accessibilityDataSensitive`](https://developer.android.com/reference/android/view/View#attr_android:accessibilityDataSensitive) attribute to protect against malicious accessibility services. This protection prevents unauthorized apps with accessibility permissions from reading sensitive view content or performing interactions unless they are declared as legitimate accessibility tools via [`isAccessibilityTool`](https://developer.android.com/reference/android/accessibilityservice/AccessibilityServiceInfo#FLAG_ACCESSIBILITY_TOOL).

## Recommendation

Apply `accessibilityDataSensitive="true"` to views that handle or display sensitive information, such as:

- Login screens (username and password fields)
- Payment and transaction confirmation screens
- Personal information forms (SSN, credit card numbers, etc.)
- Two-factor authentication inputs
- Biometric authentication prompts
- Any view displaying confidential user data

### XML Implementation

```xml
<EditText
android:id="@+id/passwordField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:accessibilityDataSensitive="true" />

<Button
android:id="@+id/confirmPayment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Confirm Payment"
android:accessibilityDataSensitive="true" />
```

### Programmatic Implementation

```kotlin
passwordField.setAccessibilityDataSensitive(View.ACCESSIBILITY_DATA_SENSITIVE_YES)
confirmButton.setAccessibilityDataSensitive(View.ACCESSIBILITY_DATA_SENSITIVE_YES)
```

## Rationale

Malicious apps can abuse Android's accessibility framework to:

- Eavesdrop on sensitive user inputs (credentials, payment details)
- Perform automated click injection on critical actions (approve transactions)
- Extract confidential information displayed on screen
- Conduct phishing attacks by monitoring user behavior

By marking views as `accessibilityDataSensitive`, the system restricts non-tool accessibility services from accessing or interacting with these views, significantly reducing the attack surface for malware that relies on accessibility permissions.

## Automatic Protection with filterTouchesWhenObscured

Apps already using [`filterTouchesWhenObscured="true"`](https://developer.android.com/reference/android/view/View#setFilterTouchesWhenObscured(boolean)) for tapjacking protection automatically gain `accessibilityDataSensitive` benefits on Android 16+. This provides an instant additional layer of defense with no extra code:

```xml
<Button
android:id="@+id/transferFunds"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:filterTouchesWhenObscured="true" />
<!-- Automatically protected from malicious accessibility services on Android 16+ -->
```

If your app already implements `filterTouchesWhenObscured` on sensitive views, you receive this protection automatically. However, explicitly setting `accessibilityDataSensitive` is recommended for clarity and to ensure protection even if `filterTouchesWhenObscured` is later changed.

## Considerations and Caveats

### Legitimate Accessibility Tools

This protection can impact legitimate accessibility services like screen readers. Users relying on accessibility tools may experience degraded functionality on marked views unless the accessibility service declares `isAccessibilityTool="true"`.

- **Testing**: Test your app with popular accessibility tools (TalkBack, Voice Access) to ensure they can still function properly with marked views.
- **User Communication**: If certain views must be marked sensitive for security, consider providing alternative accessible pathways or clear user guidance.

### API Level Compatibility

The `accessibilityDataSensitive` attribute is only available on Android 16 (API level 35) and higher. On older devices:

- The attribute is ignored; the app functions normally without this protection
- Consider using `filterTouchesWhenObscured` for broader compatibility against overlay attacks
- Implement defense-in-depth by combining multiple security measures

### Granularity

Apply the attribute judiciously:

- **Too Broad**: Marking entire screens reduces accessibility for users who need it
- **Too Narrow**: Missing critical views leaves security gaps

Focus on views that directly handle or display sensitive data, not general UI chrome.

### View Hierarchy

The `accessibilityDataSensitive` attribute can be inherited through the view hierarchy when using `View.ACCESSIBILITY_DATA_SENSITIVE_AUTO`. Plan your view structure to minimize repetition while ensuring comprehensive coverage.

## References

- [Android Developers Blog - Enhancing Android Security: Stop Malware with Accessibility Data Sensitivity](https://android-developers.googleblog.com/2025/12/enhancing-android-security-stop-malware.html)
- [Android Security: Tapjacking Mitigations](https://developer.android.com/privacy-and-security/risks/tapjacking#mitigations)
- [View.setAccessibilityDataSensitive](https://developer.android.com/reference/android/view/View#setAccessibilityDataSensitive(int))
72 changes: 72 additions & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0083/MASTG-DEMO-0083.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
platform: android
title: Detecting Accessibility Data Sensitivity in Layouts with semgrep
id: MASTG-DEMO-0083
code: [xml, kotlin]
test: MASTG-TEST-0321
---

## Sample

This sample demonstrates how to detect the use of `accessibilityDataSensitive` and `filterTouchesWhenObscured` attributes in Android layout files using Semgrep. The sample includes both properly protected views and views that lack protection.

{{ activity_login.xml # MastgTest.kt }}

### activity_login.xml

The layout file contains several EditText fields for user credentials:

1. `usernameField` - Has no protection (neither `accessibilityDataSensitive` nor `filterTouchesWhenObscured`)
2. `passwordField` - Protected with `android:accessibilityDataSensitive="true"`
3. `pinField` - Protected with `android:filterTouchesWhenObscured="true"` (which provides implicit accessibility protection on Android 16+)
4. `creditCardField` - Protected with both `android:accessibilityDataSensitive="true"` and `android:filterTouchesWhenObscured="true"`

### MastgTest.kt

The Kotlin code demonstrates programmatic configuration of accessibility data sensitivity:

1. Sets `accessibilityDataSensitive` on a button using the View API
2. Checks the current state of `accessibilityDataSensitive` on views
3. Sets `filterTouchesWhenObscured` which provides implicit protection

## Steps

Let's run our @MASTG-TOOL-0110 rule against the layout file and decompiled code.

{{ ../../../../rules/mastg-android-accessibility-data-sensitive.yaml }}

{{ run.sh }}

## Observation

The rule has identified:

1. Views with explicit `accessibilityDataSensitive` attributes in XML
2. Views with `filterTouchesWhenObscured` which provide implicit accessibility protection
3. Programmatic calls to set or check accessibility data sensitivity
4. Potentially sensitive input fields that lack any protection

{{ output.txt }}

## Evaluation

Based on the Semgrep output:

**Failures (views lacking protection):**

- `usernameField` (line 12 in activity_login.xml): An EditText for username input lacks both `accessibilityDataSensitive` and `filterTouchesWhenObscured` protection. While usernames may be less sensitive than passwords, credential fields should generally be protected.

**Passes (properly protected views):**

- `passwordField` (line 23): Protected with `android:accessibilityDataSensitive="true"` - malicious accessibility services cannot read password input
- `pinField` (line 34): Protected with `android:filterTouchesWhenObscured="true"` - gains implicit accessibility protection on Android 16+ while also preventing tapjacking
- `creditCardField` (line 45): Protected with both attributes - defense in depth approach
- `confirmButton` (line 18 in MastgTest.kt): Programmatically sets `ACCESSIBILITY_DATA_SENSITIVE_YES` for a payment confirmation button
- Runtime checks (lines 22-23): The code properly checks current sensitivity settings

**Recommendations:**

1. Add `android:accessibilityDataSensitive="true"` or `android:filterTouchesWhenObscured="true"` to `usernameField`
2. Consider using `filterTouchesWhenObscured` on all credential fields for broader protection across Android versions
3. Review all payment and transaction confirmation buttons to ensure they are protected programmatically or in XML
4. Test with legitimate accessibility tools (TalkBack, Voice Access) to ensure protected views remain accessible when needed
35 changes: 35 additions & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0083/MastgTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.owasp.mastestapp

import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity

// SUMMARY: This sample demonstrates programmatic configuration of accessibility data sensitivity in Android.

class MastgTest : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)

// PASS: [MASTG-TEST-0321] Programmatically set accessibility data sensitivity on a button
val confirmButton = findViewById<Button>(R.id.loginButton)
confirmButton.setAccessibilityDataSensitive(View.ACCESSIBILITY_DATA_SENSITIVE_YES)

// Check current sensitivity settings
val passwordField = findViewById<EditText>(R.id.passwordField)
val isDataSensitive = passwordField.accessibilityDataSensitive
val isFilteringTouches = passwordField.isFilterTouchesWhenObscured

// PASS: [MASTG-TEST-0321] Programmatically set filterTouchesWhenObscured for additional protection
val usernameField = findViewById<EditText>(R.id.usernameField)
usernameField.setFilterTouchesWhenObscured(true)

// Example: Conditionally disable protection (should be avoided for sensitive views)
// FAIL: [MASTG-TEST-0321] Never explicitly disable protection on sensitive views
// val creditCardField = findViewById<EditText>(R.id.creditCardField)
// creditCardField.setAccessibilityDataSensitive(View.ACCESSIBILITY_DATA_SENSITIVE_NO)
}
}
51 changes: 51 additions & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0083/activity_login.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- SUMMARY: This sample demonstrates various configurations of accessibility data sensitivity and filterTouchesWhenObscured in Android layouts. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">

<!-- FAIL: [MASTG-TEST-0321] Username field lacks protection from malicious accessibility services -->
<EditText
android:id="@+id/usernameField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Username"
android:inputType="text" />

<!-- PASS: [MASTG-TEST-0321] Password field is protected with explicit accessibilityDataSensitive -->
<EditText
android:id="@+id/passwordField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Password"
android:inputType="textPassword"
android:accessibilityDataSensitive="true" />

<!-- PASS: [MASTG-TEST-0321] PIN field is protected via filterTouchesWhenObscured (implicit accessibility protection on Android 16+) -->
<EditText
android:id="@+id/pinField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="PIN"
android:inputType="numberPassword"
android:filterTouchesWhenObscured="true" />

<!-- PASS: [MASTG-TEST-0321] Credit card field is protected with both attributes for defense in depth -->
<EditText
android:id="@+id/creditCardField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Credit Card Number"
android:inputType="number"
android:accessibilityDataSensitive="true"
android:filterTouchesWhenObscured="true" />

<Button
android:id="@+id/loginButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Login" />

</LinearLayout>
60 changes: 60 additions & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0083/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
=== Scanning XML Layout ===
┌─────────────────┐
│ 6 Code Findings │
└─────────────────┘

activity_login.xml
❯❱ rules.mastg-android-sensitive-view-without-protection
[MASVS-PLATFORM] Potentially sensitive view lacks accessibilityDataSensitive or
filterTouchesWhenObscured protection

18┆ <EditText
19┆ android:id="@+id/passwordField"
20┆ android:layout_width="match_parent"
21┆ android:layout_height="wrap_content"
22┆ android:hint="Password"
23┆ android:inputType="textPassword"
24┆ android:accessibilityDataSensitive="true" />

❱ rules.mastg-android-accessibility-data-sensitive-xml
[MASVS-PLATFORM] View has accessibilityDataSensitive attribute set

24┆ android:accessibilityDataSensitive="true" />

❱ rules.mastg-android-filter-touches-when-obscured-xml
[MASVS-PLATFORM] View has filterTouchesWhenObscured set (provides implicit
accessibilityDataSensitive protection on Android 16+)

33┆ android:filterTouchesWhenObscured="true" />

❱ rules.mastg-android-filter-touches-when-obscured-xml
[MASVS-PLATFORM] View has filterTouchesWhenObscured set (provides implicit
accessibilityDataSensitive protection on Android 16+)

43┆ android:filterTouchesWhenObscured="true" />

❱ rules.mastg-android-accessibility-data-sensitive-xml
[MASVS-PLATFORM] View has accessibilityDataSensitive attribute set

42┆ android:accessibilityDataSensitive="true"

=== Scanning Kotlin Code ===
┌─────────────────┐
│ 3 Code Findings │
└─────────────────┘

MastgTest.kt
❱ rules.mastg-android-set-accessibility-data-sensitive
[MASVS-PLATFORM] View's accessibility data sensitivity is being set programmatically

18┆ confirmButton.setAccessibilityDataSensitive(View.ACCESSIBILITY_DATA_SENSITIVE_YES)

❱ rules.mastg-android-get-accessibility-data-sensitive
[MASVS-PLATFORM] Code is checking view's accessibility data sensitivity

22┆ val isDataSensitive = passwordField.accessibilityDataSensitive

❱ rules.mastg-android-set-filter-touches-when-obscured
[MASVS-PLATFORM] View's filterTouchesWhenObscured is being set (provides implicit accessibility protection on Android 16+)

27┆ usernameField.setFilterTouchesWhenObscured(true)
12 changes: 12 additions & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0083/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

# Run semgrep rules on the layout XML file
echo "=== Scanning XML Layout ==="
semgrep --config ../../../../rules/mastg-android-accessibility-data-sensitive.yaml activity_login.xml --text > output.txt 2>&1

# Run semgrep rules on the Kotlin source code
echo "" >> output.txt
echo "=== Scanning Kotlin Code ===" >> output.txt
semgrep --config ../../../../rules/mastg-android-accessibility-data-sensitive.yaml MastgTest.kt --text >> output.txt 2>&1

cat output.txt
Loading