What is Intent Injection (Android)? Ways to Exploit, Examples and Impact

Learn what Intent Injection is in Android, how to exploit it with code examples, and how to secure your mobile applications against these vulnerabilities.

What is Intent Injection (Android)? Ways to Exploit, Examples and Impact

Android applications communicate through a powerful messaging system known as Intents. While this mechanism enables seamless interaction between different components and apps, it also introduces a significant security risk: Intent Injection. This vulnerability occurs when an application takes an untrusted Intent from an external source and uses it to perform an action without proper validation. For developers and security researchers, understanding this flaw is critical to securing the mobile ecosystem.

What is an Android Intent?

Before diving into the mechanics of injection, we must understand what an Intent actually is. In the Android framework, an Intent is a messaging object used to request an action from another app component. There are three primary use cases for Intents:

  1. Starting an Activity: An Activity represents a single screen in an app. You can start a new instance of an Activity by passing an Intent to startActivity().
  2. Starting a Service: A Service is a component that performs operations in the background. You can start a service to perform a one-time operation (like downloading a file) by passing an Intent to startService().
  3. Delivering a Broadcast: A broadcast is a message that any app can receive. The system delivers various broadcasts for system events, such as when the device starts charging.

Explicit vs. Implicit Intents

There are two types of intents that Jsmon users should be aware of when auditing mobile infrastructure:

  • Explicit Intents: These specify the exact component to be started by name (the fully qualified class name). These are typically used for internal app communication.
  • Implicit Intents: These do not name a specific component but instead declare a general action to perform, which allows a component from another app to handle it.

Understanding Intent Injection

Intent Injection (often referred to as Intent Redirection) happens when an application receives an Intent from an untrusted source and then uses that Intent to launch another component. Essentially, the vulnerable application acts as a "proxy," allowing an attacker to bypass security restrictions and access internal, non-exported components that would otherwise be unreachable.

In a standard Android security model, components (Activities, Services, Receivers) can be marked as android:exported="false". This means they cannot be started by external applications. However, if a vulnerable app has an exported component that accepts an Intent as an extra and passes it to a method like startActivity(), an attacker can "inject" an Intent targeting a private component.

The Vulnerable Code Pattern

A typical vulnerable implementation looks like this:

// A publicly accessible (exported) activity
public class ProxyActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // Extracting an Intent from the incoming Intent's extras
        Intent nestedIntent = (Intent) getIntent().getParcelableExtra("target_intent");
        
        // Vulnerability: Starting the nested intent without validation
        if (nestedIntent != null) {
            startActivity(nestedIntent);
        }
    }
}

In this snippet, ProxyActivity is the middleman. It takes whatever Intent is hidden inside the target_intent extra and executes it. This is the root of the Intent Injection flaw.

How to Exploit Intent Injection

Exploiting Intent Injection requires crafting a malicious application that sends a "nested" Intent to the vulnerable target. Let's look at three common exploitation scenarios.

1. Accessing Private Activities

Imagine an application has a private Activity called com.victim.app.AdminSettings which is not exported. Normally, an attacker cannot launch this. However, if the attacker finds the ProxyActivity shown above, they can use it to reach the admin settings.

Attacker Code Example:

Intent maliciousIntent = new Intent();
// Target the internal, non-exported activity
maliciousIntent.setClassName("com.victim.app", "com.victim.app.AdminSettings");

// Create the wrapper intent to hit the proxy
Intent proxyIntent = new Intent();
proxyIntent.setClassName("com.victim.app", "com.victim.app.ProxyActivity");
proxyIntent.putExtra("target_intent", maliciousIntent);

// Send it
startActivity(proxyIntent);

When the victim app receives proxyIntent, it extracts maliciousIntent and calls startActivity() on it. Since the call is now coming from within the victim's own process, the Android system allows the launch of the private AdminSettings activity.

2. Stealing Sensitive Files via FileProvider

One of the most dangerous impacts of Intent Injection is the ability to steal private files. Many apps use a FileProvider to share files securely. If an app is vulnerable to Intent Injection, an attacker can force the app to send a file to the attacker's own activity.

If the vulnerable app uses startActivityForResult(), the attacker can redirect the Intent to a FileProvider URI.

The Payload Concept:

  1. Attacker sends an Intent to the Proxy Activity.
  2. The Proxy Activity is told to launch a component with Intent.FLAG_GRANT_READ_URI_PERMISSION.
  3. The attacker points the data URI to a local file within the victim app's sandbox (e.g., content://com.victim.provider/root/data/data/com.victim.app/databases/user_creds.db).
  4. The victim app inadvertently grants the attacker permission to read its own sensitive database.

3. Abusing PendingIntents

A PendingIntent is a token that you give to a foreign application (e.g., Notification Manager, Alarm Manager), which allows the foreign application to use your application's permissions to execute a predefined piece of code. If an attacker can intercept or influence the creation of a PendingIntent, they can perform actions with the victim app's identity.

Before Android 12, PendingIntents were often created without specifying mutability. If a PendingIntent is mutable, an attacker can modify the base Intent inside it before it is triggered. This is a specialized form of Intent Injection where the "injection" happens by modifying an existing object rather than providing a new one.

Real-World Impact of Intent Injection

The consequences of this vulnerability are severe and can lead to total application compromise. Jsmon helps organizations identify their external assets, but internal application logic like this requires deep code analysis or dynamic testing.

  • Unauthorized Access to Functionality: Attackers can reach debug screens, administrative panels, or payment gateways that were intended to be hidden.
  • Data Exfiltration: Accessing internal databases, shared preferences, or sensitive files via FileProviders.
  • Account Takeover: If the app has an internal activity that handles password resets or OAuth tokens, an attacker might trigger these flows to gain control of the user's account.
  • Escalation of Privilege: An app with high permissions (like a system app) that is vulnerable to Intent Injection can be used by a malicious low-privilege app to perform system-level tasks, such as installing other packages or wiping data.

How to Prevent Intent Injection

Securing your application against Intent Injection requires a defense-in-depth approach. Here are the most effective mitigation strategies:

1. Avoid Exporting Components

The simplest fix is to not export components that don't need to be public. In your AndroidManifest.xml, ensure that android:exported="false" is set for all internal activities. Starting with Android 12, you must explicitly set this attribute for any component with an intent filter.

2. Validate the Nested Intent

If your application must accept an Intent as an extra, you must validate it before using it. This involves checking the destination component and ensuring it matches an allowlist.

Intent nestedIntent = (Intent) getIntent().getParcelableExtra("target_intent");
ComponentName componentName = nestedIntent.resolveActivity(getPackageManager());

// Check if the component belongs to your own package
if (componentName.getPackageName().equals(getPackageName())) {
    // Only allow specific, safe activities
    if (componentName.getClassName().equals("com.victim.app.SafeActivity")) {
        startActivity(nestedIntent);
    }
}

3. Use PendingIntents Safely

When using PendingIntent, always specify the mutability flag. In almost all cases, you should use PendingIntent.FLAG_IMMUTABLE. This prevents other apps from modifying the Intent.

PendingIntent pendingIntent = PendingIntent.getActivity(
    context, 
    0, 
    intent, 
    PendingIntent.FLAG_IMMUTABLE
);

4. Use Explicit Intents for Internal Communication

Never rely on implicit intents for communication between your own app's components. By using explicit intents (naming the class directly), you eliminate the risk of an attacker intercepting the message or providing a malicious substitute.

Conclusion

Intent Injection is a subtle but devastating vulnerability in the Android ecosystem. It turns an application's own features against itself, allowing attackers to bridge the gap between public interfaces and private data. By understanding the proxy-like nature of this attack and implementing strict validation on incoming data, developers can build more resilient mobile applications.

As the mobile landscape evolves, so do the methods used by attackers to find these flaws. Continuous monitoring and a proactive security posture are essential for any modern enterprise.

To proactively monitor your organization's external attack surface and catch exposures before attackers do, try Jsmon.