Skip to content

Java: Add query for exposure of sensitive information to android notifications #15281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jan 26, 2024
Merged
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
43 changes: 43 additions & 0 deletions java/ql/lib/ext/android.app.model.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,48 @@ extensions:
- ["android.app", "FragmentTransaction", True, "replace", "(int,Class,Bundle,String)", "", "Argument[1]", "fragment-injection", "manual"]
- ["android.app", "FragmentTransaction", True, "replace", "(int,Fragment)", "", "Argument[1]", "fragment-injection", "manual"]
- ["android.app", "FragmentTransaction", True, "replace", "(int,Fragment,String)", "", "Argument[1]", "fragment-injection", "manual"]
- ["android.app", "Notification$Action", True, "Action", "(int,CharSequence,PendingIntent)", "", "Argument[1]", "notification", "manual"]
- ["android.app", "Notification$Action$Builder", True, "Builder", "(Icon,CharSequence,PendingIntent)", "", "Argument[1]", "notification", "manual"]
- ["android.app", "Notification$Action$Builder", True, "Builder", "(int,CharSequence,PendingIntent)", "", "Argument[1]", "notification", "manual"]
- ["android.app", "Notification$Action$Builder", True, "addExtras", "(Bundle)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$BigPictureStyle", True, "setBigContentTitle", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$BigPictureStyle", True, "setContentDescription", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$BigPictureStyle", True, "setSummaryText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$BigTextStyle", True, "bigText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$BigTextStyle", True, "setBigContentTitle", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$BigTextStyle", True, "setSummaryText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "addAction", "(int,CharSequence,PendingIntent)", "", "Argument[1]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "addExtras", "(Bundle)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setCategory", "(String)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setChannelId", "(String)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setContent", "(RemoteViews)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setContentInfo", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setContentText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setContentTitle", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setCustomBigContentView", "(RemoteViews)", "", "Argument[0]", "notification", "manual"]
Copy link
Contributor

Choose a reason for hiding this comment

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

Can a RemoteViews contain sensitive data?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think existing models could track it, but it seems like it would theoretically be able to.

- ["android.app", "Notification$Builder", True, "setCustomContentView", "(RemoteViews)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setCustomHeadsUpContentView", "(RemoteViews)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setExtras", "(Bundle)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setGroup", "(String)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setRemoteInputHistory", "(CharSequence[])", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setSettingsText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setSortKey", "(String)", "", "Argument[0]", "notification", "manual"]
Copy link
Contributor

Choose a reason for hiding this comment

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

Can the sort key be recovered from the notification? And even if so, this doesn't very likely to receive sensitive data, does it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It can with getSortKey. Though it does indeed seem unlikely to receive sensitive data.

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, the model won't hurt, you never know what people can use as sort key 😄

- ["android.app", "Notification$Builder", True, "setSubText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setTicker", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$Builder", True, "setTicker", "(CharSequence,RemoteViews)", "", "Argument[0..1]", "notification", "manual"]
- ["android.app", "Notification$CallStyle", True, "setVerificationText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$InboxStyle", True, "addLine", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$InboxStyle", True, "setBigContentTitle", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$InboxStyle", True, "setSummaryText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$MediaStyle", True, "setRemotePlaybackInfo", "(CharSequence,int,PendingIntent)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$MessagingStyle", True, "MessagingStyle", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$MessagingStyle", True, "addMessage", "(CharSequence,long,CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$MessagingStyle", True, "addMessage", "(CharSequence,long,CharSequence)", "", "Argument[2]", "notification", "manual"]
- ["android.app", "Notification$MessagingStyle", True, "addMessage", "(CharSequence,long,Person)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$MessagingStyle", True, "setConversationTitle", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$MessagingStyle$Message", True, "Message", "(CharSequence,long,CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "Notification$MessagingStyle$Message", True, "Message", "(CharSequence,long,CharSequence)", "", "Argument[2]", "notification", "manual"]
- ["android.app", "Notification$MessagingStyle$Message", True, "Message", "(CharSequence,long,Person)", "", "Argument[0]", "notification", "manual"]
- ["android.app", "NotificationManager", True, "notify", "(String,int,Notification)", "", "Argument[2]", "pending-intents", "manual"]
- ["android.app", "NotificationManager", True, "notify", "(int,Notification)", "", "Argument[1]", "pending-intents", "manual"]
- ["android.app", "NotificationManager", True, "notifyAsPackage", "(String,String,int,Notification)", "", "Argument[3]", "pending-intents", "manual"]
Expand All @@ -38,6 +80,7 @@ extensions:
- ["android.app", "PendingIntent", False, "send", "(Context,int,Intent,PendingIntent$OnFinished,Handler)", "", "Argument[2]", "pending-intents", "manual"]
- ["android.app", "PendingIntent", False, "send", "(Context,int,Intent,PendingIntent$OnFinished,Handler,String)", "", "Argument[2]", "pending-intents", "manual"]
- ["android.app", "PendingIntent", False, "send", "(Context,int,Intent,PendingIntent$OnFinished,Handler,String,Bundle)", "", "Argument[2]", "pending-intents", "manual"]

- addsTo:
pack: codeql/java-all
extensible: summaryModel
Expand Down
42 changes: 42 additions & 0 deletions java/ql/lib/ext/androidx.core.app.model.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,50 @@ extensions:
- ["androidx.core.app", "AlarmManagerCompat", True, "setAndAllowWhileIdle", "", "", "Argument[3]", "pending-intents", "manual"]
- ["androidx.core.app", "AlarmManagerCompat", True, "setExact", "", "", "Argument[3]", "pending-intents", "manual"]
- ["androidx.core.app", "AlarmManagerCompat", True, "setExactAndAllowWhileIdle", "", "", "Argument[3]", "pending-intents", "manual"]
- ["androidx.core.app", "NotificationCompat$Action", True, "Action", "(int,CharSequence,PendingIntent)", "", "Argument[1]", "notification", "manual"]
Copy link
Contributor

Choose a reason for hiding this comment

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

Same questions/comments from above, since the APIs are nearly identical.

- ["androidx.core.app", "NotificationCompat$Action$Builder", True, "Builder", "(IconCompat,CharSequence,PendingIntent)", "", "Argument[1]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Action$Builder", True, "Builder", "(int,CharSequence,PendingIntent)", "", "Argument[1]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Action$Builder", True, "addExtras", "(Bundle)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$BigPictureStyle", True, "setBigContentTitle", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$BigPictureStyle", True, "setContentDescription", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$BigPictureStyle", True, "setSummaryText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$BigTextStyle", True, "bigText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$BigTextStyle", True, "setBigContentTitle", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$BigTextStyle", True, "setSummaryText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "addAction", "(int,CharSequence,PendingIntent)", "", "Argument[1]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "addExtras", "(Bundle)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setCategory", "(String)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setChannelId", "(String)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setContent", "(RemoteViews)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setContentInfo", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setContentText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setContentTitle", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setCustomBigContentView", "(RemoteViews)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setCustomContentView", "(RemoteViews)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setCustomHeadsUpContentView", "(RemoteViews)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setExtras", "(Bundle)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setGroup", "(String)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setRemoteInputHistory", "(CharSequence[])", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setSettingsText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setSortKey", "(String)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setSubText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setTicker", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$Builder", True, "setTicker", "(CharSequence,RemoteViews)", "", "Argument[0..1]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$CallStyle", True, "setVerificationText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$InboxStyle", True, "addLine", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$InboxStyle", True, "setBigContentTitle", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$InboxStyle", True, "setSummaryText", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$MessagingStyle", True, "addMessage", "(CharSequence,long,CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$MessagingStyle", True, "addMessage", "(CharSequence,long,CharSequence)", "", "Argument[2]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$MessagingStyle", True, "addMessage", "(CharSequence,long,Person)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$MessagingStyle", True, "setConversationTitle", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$MessagingStyle", True, "MessagingStyle", "(CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$MessagingStyle$Message", True, "Message", "(CharSequence,long,CharSequence)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$MessagingStyle$Message", True, "Message", "(CharSequence,long,CharSequence)", "", "Argument[2]", "notification", "manual"]
- ["androidx.core.app", "NotificationCompat$MessagingStyle$Message", True, "Message", "(CharSequence,long,Person)", "", "Argument[0]", "notification", "manual"]
- ["androidx.core.app", "NotificationManagerCompat", True, "notify", "(String,int,Notification)", "", "Argument[2]", "pending-intents", "manual"]
- ["androidx.core.app", "NotificationManagerCompat", True, "notify", "(int,Notification)", "", "Argument[1]", "pending-intents", "manual"]

- addsTo:
pack: codeql/java-all
extensible: summaryModel
Expand Down
22 changes: 22 additions & 0 deletions java/ql/lib/semmle/code/java/security/SensitiveUiQuery.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/** Definitions for Android Sensitive UI queries */
Copy link
Contributor

Choose a reason for hiding this comment

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

I assume you plan to add more configurations here and that's why this library file has a more general name.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed; #15396 uses the same file


import java
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.security.SensitiveActions

/** A configuration for tracking sensitive information to system notifications. */
private module NotificationTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SensitiveExpr }

predicate isSink(DataFlow::Node sink) { sinkNode(sink, "notification") }

predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
isSink(node) and exists(c)
}

predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
}

/** Taint tracking flow for sensitive data flowing to system notifications. */
module NotificationTracking = TaintTracking::Global<NotificationTrackingConfig>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// BAD: `password` is exposed in a notification.
void confirmPassword(String password) {
NotificationManager manager = NotificationManager.from(this);
manager.send(
new Notification.Builder(this, CHANNEL_ID)
.setContentText("Your password is: " + password)
.build());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Sensitive information such as passwords or two-factor authentication (2FA) codes should not be exposed in a system notification.
Notifications should not be considered secure, as other untrusted applications may be able to use a
<code>NotificationListenerService</code> to read the contents of notifications.
</p>
</overview>

<recommendation>
<p>
Do not expose sensitive data in notifications.
</p>
</recommendation>

<example>
<p>
In the following sample, the <code>password</code> is sent as part of a notification.
This can allow another application to read this password.
</p>

<sample src="AndroidSensitiveNotifications.java"/>
</example>

<references>
<li>
OWASP Mobile Application Security: <a href="https://mas.owasp.org/MASTG/Android/0x05d-Testing-Data-Storage/#app-notifications">Android Data Storage - Application Notifications</a>
</li>
</references>

</qhelp>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @name Exposure of sensitive information to notifications
* @id java/android/sensitive-notification
* @kind path-problem
* @description Sensitive information exposed in a system notification can be read by an unauthorized application.
* @problem.severity error
* @precision medium
* @security-severity 6.5
* @tags security
* external/cwe/cwe-200
*/

import java
import java
import semmle.code.java.security.SensitiveUiQuery
import NotificationTracking::PathGraph

from NotificationTracking::PathNode source, NotificationTracking::PathNode sink
where NotificationTracking::flowPath(source, sink)
select sink, source, sink, "This $@ is exposed in a system notification.", source,
"sensitive information"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: newQuery
---
* Added a new query `java/android/sensitive-notification` to detect instances of sensitive data being exposed through Android notifications.
Loading