Remediation for Intent Redirection Vulnerability

This information is intended for developers with app(s) that contain the Intent Redirection Vulnerability.

What’s happening

One or more of your apps contain an Intent Redirection issue which can allow malicious apps to access private app components or files. Vulnerable locations in your app can be found in the Play Console notification for your app. If a location ends with “(in dynamically loaded code)” then the location is in code dynamically loaded by the app or by libraries used by the app. Applications typically use dynamically loaded code through on-demand feature delivery, though other unrecommended techniques exist (some unrecommended techniques also violate the Google Play policy and should not be used). Additionally, packers can transform application code into dynamically loaded code. Please review the detailed steps below to fix the issue with your apps.

After the deadlines shown in your Play Console, any apps that contain unfixed security vulnerabilities will be removed from Google Play.

Action required​

  1. Sign in to your Play Console, and navigate to the Alerts section to see which apps are affected and the deadlines to resolve these issues.
  2. Update your affected apps using the steps highlighted below.
  3. Submit the updated versions of your affected apps.

Upon resubmission, your app will be reviewed again. This process can take several hours. If the app passes review and is published successfully, then no further action is required. If the app fails review, then the new app version will not be published and you will receive an email notification.

Additional details

Using an untrusted Intent to launch a component (for example, by calling startActivity) or to return data (for example, by calling setResult) is dangerous and can allow malicious apps to cause the following problems: 

  1. Steal sensitive files or system data (like SMS messages) from your app
  2. Launch your app’s private components with poisoned arguments.

It is important that your app does not call startActivity, startService, sendBroadcast, or setResult on untrusted Intents without validating or sanitizing these Intents.

We recommend that you prevent this vulnerability in one of the following ways:

Option 1: Make the affected app component, from which the extracted Intent is redirected, private.

If the affected app component does not need to receive Intents from other apps then you can make that app component private by setting android:exported=”false” in your Manifest.

Option 2: Ensure that the extracted Intent is from a trustworthy source.

You can verify that the originating Activity can be trusted using methods like getCallingActivity. For example:

 // check if the originating Activity is from trusted package
 if (getCallingActivity().getPackageName().equals(“known”)) {
   Intent intent = getIntent();
   // extract the nested Intent
   Intent forward = (Intent) intent.getParcelableExtra(“key”);
   // redirect the nested Intent
   startActivity(forward);
 }

Note:

  • Checking if getCallingActivity() returns a non-null value is insufficient to prevent the vulnerability. Malicious apps can supply a null value for this function.
  • In the case of Google Play Services SMS Retriever Auth, protecting a broadcast receiver with the SEND_PERMISSION will ensure that an Intent comes from Play Services.

Option 3: Ensure that the to-be-redirected Intent is not harmful.

You should verify that the redirected Intent

  1. will not be sent to any of your app’s private components, and
  2. will not be sent to an external app's component. If the redirect is intended to target an external app, be sure the intent will not grant a URI permission to one of your app’s private content providers or system data.

Apps can check which component will be used to handle the Intent before redirecting it using methods like resolveActivity. For example:

 Intent intent = getIntent();
 // extract the nested Intent
 Intent forward = (Intent) intent.getParcelableExtra(“key”);
 // get the component name
 ComponentName name = forward.resolveActivity(getPackageManager());
 // check that the package name and class name are as intended
 if (name.getPackageName().equals(“safe_package”) &&
     name.getClassName().equals(“safe_class”)) {
   // redirect the nested Intent
   startActivity(forward);
 }

Apps can check whether an Intent grants a URI permission using methods like getFlags. For example:

 // extract the nested Intent
 Intent forward = (Intent) intent.getParcelableExtra(“key”);
 // get the flags
 int flags = forward.getFlags();
 // check that the nested intent does not grant URI permissions
 if ((flags & Intent.FLAG_GRANT_READ_URI_PERMISSION == 0) &&
     (flags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION == 0)) {
   // redirect the nested Intent
   startActivity(forward);
 }

Apps can also remove grants of URI permissions using removeFlags. For example:

 // untrusted Intent
 Intent intent = getIntent();
 // remove the grant URI permissions in the untrusted Intent
 intent.removeFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
 intent.removeFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
 // pass the untrusted Intent
 setResult(intent);

Understanding Alerts and Choosing a Prevention Option 

The Play Console alert reports where your app calls startActivity, startActivityForResult, startService, sendBroadcast, or setResult using an untrusted Intent. To better understand which prevention option is most appropriate, trace back and look at callers of methods to find where the untrusted Intent originates. For example, for Option 1, trace back to determine which component to make private.

We’re here to help

If you have technical questions about the vulnerability, you can post to Stack Overflow and use the tag “android-security.” For clarification on steps you need to take to resolve this issue, you can contact our developer support team.

Was this helpful?

How can we improve it?
false
Google apps
Main menu
1866793986516820300
true
Search Help Center
true
true
true
true
true
5016068