Intent Redirection Vulnerability
Risk: High - MASVS_CODE_4
Overview
An intent redirection occurs when an attacker can partly or fully control the contents of an intent used to launch a new component in the context of a vulnerable app.
The intent used to launch the new component can be supplied in several ways, most commonly either as a serialized intent in an
extrasfield, or marshaled to a string and parsed. Partial control of parameters can also lead to the same result.
The Code: Intent Redirection Vulnerability
Here’s the code we’re analyzing:
Intent intent = getIntent();
// Get the component name of the nested intent.
Intent forward = (Intent) intent.getParcelableExtra("key");
ComponentName name = forward.resolveActivity(getPackageManager());
// Check that the package name and class name contain the expected values.
if (name.getPackageName().equals("safe_package") &&
name.getClassName().equals("safe_class")) {
// Redirect the nested intent.
startActivity(forward);
}Step-by-Step Explanation
Receiving an External Intent:
Intent intent = getIntent();The app receives an
Intentfrom an external source.Extracting a Nested Intent:
Intent forward = (Intent) intent.getParcelableExtra("key");The app extracts another
Intent(called a nested intent) from the originalIntentusing the key"key".Resolving the Component of the Nested Intent:
ComponentName name = forward.resolveActivity(getPackageManager());The code determines the
Package NameandClass Nameof the nested intent’s target component.Validating the Target Component:
if (name.getPackageName().equals("safe_package") && name.getClassName().equals("safe_class")) {It checks if the target package and class match the expected values (
safe_packageandsafe_class).Redirecting the Nested Intent:
startActivity(forward);If the validation passes, the app redirects the nested intent using
startActivity().
Where is the Vulnerability?
The vulnerability lies in the validation logic.
The code only checks the package name and class name of the nested intent.
However, an attacker can craft a malicious nested intent that looks legitimate (
safe_packageandsafe_classmatch) but contains harmful payloads.
Example of Exploiting the Vulnerability
An attacker can create an intent like this:
Intent maliciousIntent = new Intent();
Intent nestedIntent = new Intent();
nestedIntent.setComponent(new ComponentName("safe_package", "safe_class"));
// Add malicious data or actions
nestedIntent.putExtra("exploit_data", "malicious_data");
// Wrap the nested intent in the outer intent
maliciousIntent.putExtra("key", nestedIntent);
startActivity(maliciousIntent);Here’s what happens:
The outer intent contains a nested intent (
nestedIntent).The nested intent’s
ComponentNamematches the expected values (safe_packageandsafe_class), so the validation passes.The app executes
startActivity(forward)and processes the malicious payload inside the nested intent (exploit_data).If
safe_classhas a vulnerability or doesn’t properly validate the payload, the attack succeeds.
How to Mitigate the Vulnerability
As a rule of thumb, it's best to avoid exposing functionality related to redirecting nested intents. However, if the situation demands, use the following strategies for mitigation:
Check where the intent is being redirected.
Use PendingIntent objects. This prevents your component from being exported and makes the target action intent immutable.
Use IntentSanitizer to make a sanitized copy of an Intent
Apps can check where an intent is being redirected using methods such as ResolveActivity:
Intent intent = getIntent()
// Get the component name of the nested intent.
Intent forward = (Intent) intent.getParcelableExtra("key");
ComponentName name = forward.resolveActivity(getPackageManager());
// Check that the package name and class name contain the expected values.
if (name.getPackageName().equals("safe_package") &&
name.getClassName().equals("safe_class")) {
// Redirect the nested intent.
startActivity(forward);
}Apps can use IntentSanitizer using logic similar to the following:
Intent intent = new IntentSanitizer.Builder()
.allowComponent("com.example.ActivityA")
.allowData("com.example")
.allowType("text/plain")
.build()
.sanitizeByThrowing(intent);Resources
Last updated
Was this helpful?
