CodeQL documentation

Use of implicit PendingIntents

ID: java/android/implicit-pendingintents
Kind: path-problem
Security severity: 8.2
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-927
Query suites:
   - java-code-scanning.qls
   - java-security-extended.qls
   - java-security-and-quality.qls

Click to see the query in the CodeQL repository

A PendingIntent is used to wrap an Intent that will be supplied and executed by another application. When the Intent is executed, it behaves as if it were run directly by the supplying application, using the privileges of that application.

If a PendingIntent is configured to be mutable, the fields of its internal Intent can be changed by the receiving application if they were not previously set. This means that a mutable PendingIntent that has not defined a destination component (that is, an implicit PendingIntent) can be altered to execute an arbitrary action with the privileges of the application that created it.

A malicious application can access an implicit PendingIntent as follows:

  • It is wrapped and sent as an extra of another implicit Intent.

  • It is sent as the action of a Slide.

  • It is sent as the action of a Notification.

On gaining access, the attacker can modify the underlying Intent and execute an arbitrary action with elevated privileges. This could give the malicious application access to private components of the victim application, or the ability to perform actions without having the necessary permissions.

Recommendation

Avoid creating implicit PendingIntents. This means that the underlying Intent should always have an explicit destination component.

When you add the PendingIntent as an extra of another Intent, make sure that this second Intent also has an explicit destination component, so that it is not delivered to untrusted applications.

Create the PendingIntent using the flag FLAG_IMMUTABLE whenever possible, to prevent the destination component from modifying empty fields of the underlying Intent.

Example

In the following examples, a PendingIntent is created and wrapped as an extra of another Intent.

In the first example, both the PendingIntent and the Intent it is wrapped in are implicit, making them vulnerable to attack.

In the second example, the issue is avoided by adding explicit destination components to the PendingIntent and the wrapping Intent.

The third example uses the FLAG_IMMUTABLE flag to prevent the underlying Intent from being modified by the destination component.

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;

public class ImplicitPendingIntents extends Activity {

	public void onCreate(Bundle savedInstance) {
		{
			// BAD: an implicit Intent is used to create a PendingIntent.
			// The PendingIntent is then added to another implicit Intent
			// and started.
			Intent baseIntent = new Intent();
			PendingIntent pi =
					PendingIntent.getActivity(this, 0, baseIntent, PendingIntent.FLAG_ONE_SHOT);
			Intent fwdIntent = new Intent("SOME_ACTION");
			fwdIntent.putExtra("fwdIntent", pi);
			sendBroadcast(fwdIntent);
		}

		{
			// GOOD: both the PendingIntent and the wrapping Intent are explicit.
			Intent safeIntent = new Intent(this, AnotherActivity.class);
			PendingIntent pi =
					PendingIntent.getActivity(this, 0, safeIntent, PendingIntent.FLAG_ONE_SHOT);
			Intent fwdIntent = new Intent();
			fwdIntent.setClassName("destination.package", "DestinationClass");
			fwdIntent.putExtra("fwdIntent", pi);
			startActivity(fwdIntent);
		}

		{
			// GOOD: The PendingIntent is created with FLAG_IMMUTABLE.
			Intent baseIntent = new Intent("SOME_ACTION");
			PendingIntent pi =
					PendingIntent.getActivity(this, 0, baseIntent, PendingIntent.FLAG_IMMUTABLE);
			Intent fwdIntent = new Intent();
			fwdIntent.setClassName("destination.package", "DestinationClass");
			fwdIntent.putExtra("fwdIntent", pi);
			startActivity(fwdIntent);
		}
	}
}

References

  • © GitHub, Inc.
  • Terms
  • Privacy