Skip to content

MASTG-DEMO-0078: App Leaking Sensitive Data via Notifications

Download MASTG-DEMO-0078 APK Open MASTG-DEMO-0078 Folder Build MASTG-DEMO-0078 APK

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 adb 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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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()

}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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>

Steps

Let's run our semgrep rule against the reversed Java code.

../../../../rules/mastg-android-sensitive-data-in-notifications.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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(...)

And another one against the sample manifest file.

../../../../rules/mastg-android-sensitive-data-in-notifications-manifest.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
rules:
  - id: mastg-android-sensitive-data-in-notifications-manifest
    languages:
      - xml
    severity: WARNING
    metadata:
      summary: This rule inspects 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"
  - id: mastg-android-minsdkversion
    languages:
      - xml
    severity: INFO
    metadata:
      summary: This rule inspects AndroidManifest.xml to obtain the minSdkVersion value.
    message: "[MASVS-PLATFORM-3] Ensure that the minSdkVersion is evaluated for notification exposure on older Android versions"
    pattern: android:minSdkVersion="$X"
run.sh
1
2
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

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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
┌─────────────────┐
│ 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();
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
┌─────────────────┐
│ 2 Code Findings │
└─────────────────┘

    AndroidManifest_reversed.xml
     ❱ rules.mastg-android-minsdkversion
          [MASVS-PLATFORM-3] Ensure that the minSdkVersion is evaluated for notification exposure on older
          Android versions                                                                                

           11┆ android:minSdkVersion="29"

    ❯❱ 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"/>

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 notification contains sensitive data, specifically a first and a last name (PII).