Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
80fecef
Deprecate TEST-0005. Port TEST-0005 to v2
Diolor Sep 18, 2025
1e4985d
Move to test-beta/ folder
Diolor Sep 18, 2025
2df7820
Wording correction
Diolor Sep 18, 2025
c7ed7f4
Add sensitive notifications demo
Diolor Sep 18, 2025
48d30d7
Add sensitive notifications demo
Diolor Sep 18, 2025
e66dd13
Fix md lint error
Diolor Sep 19, 2025
b4c2ecd
Update demos/android/MASVS-STORAGE/MASTG-DEMO-xxx/MASTG-DEMO-xxx.md
Diolor Sep 25, 2025
ce348c2
Update demos/android/MASVS-STORAGE/MASTG-DEMO-xxx/MASTG-DEMO-xxx.md
Diolor Sep 25, 2025
51b3e6b
Update demos/android/MASVS-STORAGE/MASTG-DEMO-xxx/MASTG-DEMO-xxx.md
Diolor Sep 25, 2025
5c2aa3e
Apply suggestion from @sushi2k
Diolor Sep 25, 2025
8bafaa2
Apply suggestion from @sushi2k
Diolor Sep 25, 2025
c57ce0d
Apply suggestion from @sushi2k
Diolor Sep 25, 2025
a16be36
Add note
Diolor Sep 25, 2025
d736fd4
Move demo + test to PLATFORM
Diolor Sep 25, 2025
abbdadf
Fix outputs and special chars
Diolor Sep 25, 2025
3b96e8b
Fix semgrep
Diolor Sep 25, 2025
c0d335f
Update tests-beta/android/MASVS-PLATFORM/MASTG-TEST-00x05.md
Diolor Sep 25, 2025
e620f52
Update tests-beta/android/MASVS-PLATFORM/MASTG-TEST-00x05.md
Diolor Sep 25, 2025
9cbf755
Fix lint
Diolor Sep 26, 2025
a048383
Move to privacy
Diolor Oct 2, 2025
a687e22
Typos
Diolor Oct 2, 2025
1f78d61
Enhance test case description for notification handling and sensitive…
Diolor Oct 2, 2025
a8773fd
Allocate IDs
Diolor Oct 20, 2025
dcb85ec
Allocate IDs
Diolor Oct 20, 2025
9ddba98
Allocate IDs
Diolor Oct 20, 2025
97a1108
Deprecate TEST-0005. Port TEST-0005 to v2
Diolor Sep 18, 2025
d8bf7a2
Move to test-beta/ folder
Diolor Sep 18, 2025
3ca2a77
Wording correction
Diolor Sep 18, 2025
81a8ea9
Add sensitive notifications demo
Diolor Sep 18, 2025
3276753
Add sensitive notifications demo
Diolor Sep 18, 2025
c2be37f
Fix md lint error
Diolor Sep 19, 2025
62f5b93
Update demos/android/MASVS-STORAGE/MASTG-DEMO-xxx/MASTG-DEMO-xxx.md
Diolor Sep 25, 2025
05cecdc
Update demos/android/MASVS-STORAGE/MASTG-DEMO-xxx/MASTG-DEMO-xxx.md
Diolor Sep 25, 2025
22076ee
Update demos/android/MASVS-STORAGE/MASTG-DEMO-xxx/MASTG-DEMO-xxx.md
Diolor Sep 25, 2025
dace008
Apply suggestion from @sushi2k
Diolor Sep 25, 2025
72518d6
Apply suggestion from @sushi2k
Diolor Sep 25, 2025
152a357
Apply suggestion from @sushi2k
Diolor Sep 25, 2025
0f6a668
Add note
Diolor Sep 25, 2025
76f8e32
Move demo + test to PLATFORM
Diolor Sep 25, 2025
234eb48
Fix outputs and special chars
Diolor Sep 25, 2025
2e591b7
Fix semgrep
Diolor Sep 25, 2025
e313e3b
Update tests-beta/android/MASVS-PLATFORM/MASTG-TEST-00x05.md
Diolor Sep 25, 2025
13d100b
Update tests-beta/android/MASVS-PLATFORM/MASTG-TEST-00x05.md
Diolor Sep 25, 2025
81edfa9
Fix lint
Diolor Sep 26, 2025
41e4b31
Move to privacy
Diolor Oct 2, 2025
439ec33
Typos
Diolor Oct 2, 2025
befaad8
Enhance test case description for notification handling and sensitive…
Diolor Oct 2, 2025
5a642bc
Allocate IDs
Diolor Oct 20, 2025
8bfe28c
Allocate IDs
Diolor Oct 20, 2025
7e76e2e
Allocate IDs
Diolor Oct 20, 2025
98711a1
Merge remote-tracking branch 'origin/port-MASTG-TEST-0005' into port-…
Diolor Oct 20, 2025
e8da102
Fix ids
Diolor Oct 20, 2025
7820f31
Merge branch 'OWASP:master' into port-MASTG-TEST-0005
Diolor Oct 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
32 changes: 32 additions & 0 deletions demos/android/MASVS-PRIVACY/MASTG-DEMO-0065/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MASTestApp"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustResize"
android:theme="@style/Theme.MASTestApp">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
android:compileSdkVersion="35"
android:compileSdkVersionCodename="15"
package="org.owasp.mastestapp"
platformBuildVersionCode="35"
platformBuildVersionName="15">
<uses-sdk
android:minSdkVersion="29"
android:targetSdkVersion="35"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<permission
android:name="org.owasp.mastestapp.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
android:protectionLevel="signature"/>
<uses-permission android:name="org.owasp.mastestapp.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"/>
<application
android:theme="@style/Theme.MASTestApp"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:debuggable="true"
android:testOnly="true"
android:allowBackup="true"
android:supportsRtl="true"
android:extractNativeLibs="false"
android:fullBackupContent="@xml/backup_rules"
android:roundIcon="@mipmap/ic_launcher_round"
android:appComponentFactory="androidx.core.app.CoreComponentFactory"
android:dataExtractionRules="@xml/data_extraction_rules">
<activity
android:theme="@style/Theme.MASTestApp"
android:name="org.owasp.mastestapp.MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name="androidx.compose.ui.tooling.PreviewActivity"
android:exported="true"/>
<activity
android:name="androidx.activity.ComponentActivity"
android:exported="true"/>
<provider
android:name="androidx.startup.InitializationProvider"
android:exported="false"
android:authorities="org.owasp.mastestapp.androidx-startup">
<meta-data
android:name="androidx.emoji2.text.EmojiCompatInitializer"
android:value="androidx.startup"/>
<meta-data
android:name="androidx.lifecycle.ProcessLifecycleInitializer"
android:value="androidx.startup"/>
<meta-data
android:name="androidx.profileinstaller.ProfileInstallerInitializer"
android:value="androidx.startup"/>
</provider>
<receiver
android:name="androidx.profileinstaller.ProfileInstallReceiver"
android:permission="android.permission.DUMP"
android:enabled="true"
android:exported="true"
android:directBootAware="false">
<intent-filter>
<action android:name="androidx.profileinstaller.action.INSTALL_PROFILE"/>
</intent-filter>
<intent-filter>
<action android:name="androidx.profileinstaller.action.SKIP_FILE"/>
</intent-filter>
<intent-filter>
<action android:name="androidx.profileinstaller.action.SAVE_PROFILE"/>
</intent-filter>
<intent-filter>
<action android:name="androidx.profileinstaller.action.BENCHMARK_OPERATION"/>
</intent-filter>
</receiver>
</application>
</manifest>
41 changes: 41 additions & 0 deletions demos/android/MASVS-PRIVACY/MASTG-DEMO-0065/MASTG-DEMO-0065.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
platform: android
title: App Leaking Sensitive Data via Notifications
id: MASTG-DEMO-0065
code: [kotlin]
test: MASTG-TEST-0296
tools: [MASTG-TOOL-0110]
---

### Sample

The following sample code contains:

- the Kotlin code that creates a notification with the `NotificationManager` class and exposes sensitive data.
- the AndroidManifest.xml that declares the runtime permission `POST_NOTIFICATIONS` permission that allows the app to post notifications (Android API 33 and higher).

Note: To execute the test on a device, we must ensure that the app has the `POST_NOTIFICATIONS` permission granted. This can be done either via the @MASTG-TOOL-0004 command, such as `adb shell pm grant org.owasp.mastestapp android.permission.POST_NOTIFICATIONS` or by navigating to the app settings on the device and manually enabling the permission.

{{ MastgTest.kt # AndroidManifest.xml }}

### Steps

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

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

And another one against the sample manifest file.

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

{{ run.sh }}

### Observation

The rule detected two instances in the code where the `setContentTitle` API is used to set the notification title, and 2 cases where the `setContentText` API is used to set the notification text. It also identified the location in the manifest file where the POST_NOTIFICATIONS permission is declared.

{{ output.txt # output2.txt }}

### Evaluation

After reviewing the decompiled code at the location specified in the output (file and line number), we can conclude that the test fails because the file written by this instance contains sensitive data, specifically a first and a last name (PII).
61 changes: 61 additions & 0 deletions demos/android/MASVS-PRIVACY/MASTG-DEMO-0065/MastgTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.owasp.mastestapp

//noinspection SuspiciousImport
import android.R
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import androidx.core.app.NotificationCompat

class MastgTest(private val context: Context) {

val notificationManager =
(context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).apply {
createNotificationChannel(
NotificationChannel(
"TEST_CHANNEL_ID",
"Test Channel",
NotificationManager.IMPORTANCE_DEFAULT
)
)
}

val sensitiveTitle = "Hi John Doe"
val sensitiveText = "Hi John Doe <- This is a sensitive string containing PII"
fun mastgTest(): String {

notificationManager.notify(1, createNotification())
notificationManager.notify(2, createNotificationOnChannel())
notificationManager.notify(3, createNotificationCompat())
notificationManager.notify(4, createNotificationCompatOnChannel())

return sensitiveText
}

private fun createNotification() = Notification.Builder(context)
.setContentTitle(sensitiveTitle)
.setContentText(sensitiveText)
.setSmallIcon(R.drawable.ic_menu_info_details)
.build()

private fun createNotificationOnChannel() = Notification.Builder(context, "TEST_CHANNEL_ID")
.setContentTitle(sensitiveTitle)
.setContentText(sensitiveText)
.setSmallIcon(R.drawable.ic_menu_info_details)
.build()

private fun createNotificationCompat() = NotificationCompat.Builder(context)
.setContentTitle(sensitiveTitle)
.setContentText(sensitiveText)
.setSmallIcon(R.drawable.ic_menu_info_details)
.build()

private fun createNotificationCompatOnChannel() =
NotificationCompat.Builder(context, "TEST_CHANNEL_ID")
.setContentTitle(sensitiveTitle)
.setContentText(sensitiveText)
.setSmallIcon(R.drawable.ic_menu_info_details)
.build()

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

import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.util.Log;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;

/* compiled from: MastgTest.kt */
@Metadata(d1 = {"\u0000(\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0003\n\u0002\u0018\u0002\n\u0002\b\u0003\n\u0002\u0010\u000e\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0003\b\u0007\u0018\u00002\u00020\u0001B\u000f\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0004\b\u0004\u0010\u0005J\u0006\u0010\n\u001a\u00020\u000bJ\u000e\u0010\f\u001a\u00020\r2\u0006\u0010\u000e\u001a\u00020\u000bJ\u000e\u0010\u000f\u001a\u00020\r2\u0006\u0010\u000e\u001a\u00020\u000bR\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000R\u0011\u0010\u0006\u001a\u00020\u0007¢\u0006\b\n\u0000\u001a\u0004\b\b\u0010\t¨\u0006\u0010"}, d2 = {"Lorg/owasp/mastestapp/MastgTest;", "", "context", "Landroid/content/Context;", "<init>", "(Landroid/content/Context;)V", "notificationManager", "Landroid/app/NotificationManager;", "getNotificationManager", "()Landroid/app/NotificationManager;", "mastgTest", "", "createNotification", "Landroid/app/Notification;", "sensitiveString", "createNotificationOnChannel", "app_debug"}, k = 1, mv = {2, 0, 0}, xi = 48)
/* loaded from: classes3.dex */
public final class MastgTest {
public static final int $stable = 8;
private final Context context;
private final NotificationManager notificationManager;

public MastgTest(Context context) {
Intrinsics.checkNotNullParameter(context, "context");
this.context = context;
Object systemService = this.context.getSystemService("notification");
Intrinsics.checkNotNull(systemService, "null cannot be cast to non-null type android.app.NotificationManager");
this.notificationManager = (NotificationManager) systemService;
}

public final NotificationManager getNotificationManager() {
return this.notificationManager;
}

public final String mastgTest() {
Log.d("MASTG-TEST", "Hello from the OWASP MASTG Test app.");
Notification it = createNotification("Hello from the OWASP MASTG Test app.");
this.notificationManager.notify(1, it);
Notification it2 = createNotificationOnChannel("Hello from the OWASP MASTG Test app.");
this.notificationManager.notify(2, it2);
return "Hello from the OWASP MASTG Test app.";
}

public final Notification createNotification(String sensitiveString) {
Intrinsics.checkNotNullParameter(sensitiveString, "sensitiveString");
Notification notificationBuild = new Notification.Builder(this.context).setContentTitle("MASTG Test").setContentText(sensitiveString).build();
Intrinsics.checkNotNullExpressionValue(notificationBuild, "build(...)");
return notificationBuild;
}

public final Notification createNotificationOnChannel(String sensitiveString) {
Intrinsics.checkNotNullParameter(sensitiveString, "sensitiveString");
Notification notificationBuild = new Notification.Builder(this.context, "TEST_CHANNEL_ID").setContentTitle("MASTG Test").setContentText(sensitiveString).build();
Intrinsics.checkNotNullExpressionValue(notificationBuild, "build(...)");
return notificationBuild;
}
}
24 changes: 24 additions & 0 deletions demos/android/MASVS-PRIVACY/MASTG-DEMO-0065/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@


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

MastgTest_reversed.java
❯❱ rules.mastg-android-sensitive-data-in-notifications
[MASVS-PLATFORM-3] Ensure that notifications do not contain sensitive information

41┆ Notification notificationBuild = new
Notification.Builder(this.context).setContentTitle("MASTG
Test").setContentText(sensitiveString).build();
⋮┆----------------------------------------
41┆ Notification notificationBuild = new
Notification.Builder(this.context).setContentTitle("MASTG
Test").setContentText(sensitiveString).build();
⋮┆----------------------------------------
48┆ Notification notificationBuild = new Notification.Builder(this.context,
"TEST_CHANNEL_ID").setContentTitle("MASTG Test").setContentText(sensitiveString).build();
⋮┆----------------------------------------
48┆ Notification notificationBuild = new Notification.Builder(this.context,
"TEST_CHANNEL_ID").setContentTitle("MASTG Test").setContentText(sensitiveString).build();

12 changes: 12 additions & 0 deletions demos/android/MASVS-PRIVACY/MASTG-DEMO-0065/output2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@


┌────────────────┐
│ 1 Code Finding │
└────────────────┘

AndroidManifest_reversed.xml
❯❱ rules.mastg-android-sensitive-data-in-notifications-manifest
[MASVS-PLATFORM-3] Ensure that notifications do not contain sensitive information

14┆ <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

3 changes: 3 additions & 0 deletions demos/android/MASVS-PRIVACY/MASTG-DEMO-0065/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
NO_COLOR=true semgrep -c ../../../../rules/mastg-android-sensitive-data-in-notifications.yml ./MastgTest_reversed.java --text > output.txt

NO_COLOR=true semgrep -c ../../../../rules/mastg-android-sensitive-data-in-notifications-manifest.yml ./AndroidManifest_reversed.xml --text > output2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
rules:
- id: mastg-android-sensitive-data-in-notifications-manifest
languages:
- xml
severity: WARNING
metadata:
summary: This rule inpects AndroidManifest.xml for notification post permission. Notification may contain sensitive data.
message: "[MASVS-PLATFORM-3] Ensure that notifications do not contain sensitive information"
pattern: android:name="android.permission.POST_NOTIFICATIONS"
11 changes: 11 additions & 0 deletions rules/mastg-android-sensitive-data-in-notifications.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
rules:
- id: mastg-android-sensitive-data-in-notifications
languages:
- java
severity: WARNING
metadata:
summary: This rule looks for notifications that may contain sensitive data.
message: "[MASVS-PLATFORM-3] Ensure that notifications do not contain sensitive information"
pattern-either:
- pattern: $X.setContentTitle(...)
- pattern: $X.setContentText(...)
34 changes: 34 additions & 0 deletions tests-beta/android/MASVS-PRIVACY/MASTG-TEST-0296.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
platform: android
title: App Exposing Sensitive Data via Notifications
id: MASTG-TEST-0296
apis: [NotificationManager]
type: [static, dynamic]
weakness: MASWE-0054
prerequisites:
- identify-sensitive-data
profiles: [P]
---

## Overview

This test verifies that the app handles notifications correctly, ensuring that sensitive information—such as personally identifiable information (PII), one-time passwords (OTPs), or other sensitive data like health or financial details—is not exposed. On Android, developers typically request the runtime permission `POST_NOTIFICATIONS` that allows the app to send notifications. The creation of notifications can be handled through [`NotificationCompat.Builder`](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder) or `setContentTitle` or `setContentText` from [`Notification.Builder`](https://developer.android.com/reference/android/app/Notification.Builder).

The usage of notifications shouldn't expose sensitive information that might otherwise be accidentally disclosed via e.g. shoulder surfing or sharing the device with another person.

## Steps

1. Reverse engineer the app (@MASTG-TECH-0017).
2. Run a static analysis tool such as @MASTG-TOOL-0110 on the reverse-engineered app to identify if the `POST_NOTIFICATIONS` permission is declared in the manifest file (for the above Android API 33). This would indicate that the app generates notifications.
3. Run a static analysis tool such as @MASTG-TOOL-0110 on the reverse-engineered app's source code to identify the usage of the notification APIs, or run the app and use @MASTG-TECH-0033 and a tool like @MASTG-TOOL-0001 and start tracing all calls to functions related to the notifications creation.

## Observation

The output should contain:

- the `POST_NOTIFICATIONS` permission, if declared in the manifest file, and
- a list of locations where notification APIs are used.

## Evaluation

The test case fails if sensitive data is found in any notification created by the app.
3 changes: 3 additions & 0 deletions tests/android/MASVS-STORAGE/MASTG-TEST-0005.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ masvs_v1_levels:
- L1
- L2
profiles: [L1, L2]
status: deprecated
covered_by: [MASWE-0296]
deprecation_note: New version available in MASTG V2
---

## Overview
Expand Down