Sender of Pending Intents

OWASP category: MASVS-CODE: Code Quality

Overview

Using PendingIntent.getCreator*() or PendingIntent.getTarget*() to determine whether to trust a PendingIntent's sender creates an exploitation risk.

PendingIntent.getCreator*() or PendingIntent.getTarget*() returns the PendingIntent's creator, which does not always match its sender. The creator may be trusted, but the sender should never be trusted, as the sender might be a malicious app that acquired another app's PendingIntent using a variety of mechanisms, for example:

An example of a legitimate use of PendingIntent.getCreator*() or PendingIntent.getTarget*() would be to show the icon of the app that will be started by the PendingIntent.

Impact

Trusting a PendingIntent's sender because you queried (and trust) the creator can lead to vulnerabilities. If an app trusts the PendingIntent's sender based on its creator, and then shares its authentication or authorization logic, then whenever the PendingIntent's sender is a malicious app, this would lead to an authentication bypass or potentially even remote code execution based on invalidated, untrusted input, depending on the implementation of the vulnerable application's code.

Mitigations

Distinguish between sender and creator

Any type of authentication or authorization logic performed when receiving a PendingIntent must not be based on assumptions regarding the PendingIntent's creator identified using either PendingIntent.getCreator*() or PendingIntent.getTarget*().

Use alternative ways to validate callers

If you need to authenticate the caller, instead of using PendingIntent, you should use a Service or ContentProvider – both allow fetching the caller UID with Binder.getCallingUid() when you are in the context of dispatching an incoming IPC. The UID can be queried later by using PackageManager.getPackagesForUid().

Another approach, available from API level 34, would be to use BroadcastReceiver.getSentFromUid() or BroadcastReceiver.getSentFromPackage() if the sender opted in to sharing identity during broadcast using BroadcastOptions.isShareIdentityEnabled().

You should always check if the calling package has the expected signature, as sideloaded packages can have package names overlapping with ones from the Play Store.

Resources