Intent Forwarding
ID |
kotlin.android_intent_forwarding |
Severity |
high |
Resource |
Access Control |
Language |
Kotlin |
Tags |
CWE:926, CWE:940, MASVS:MSTG-PLATFORM-4, NIST.SP.800-53, OWASP:2021:A1, OWASP:2021:A4, PCI-DSS:6.5.10, android |
Description
Intent forwarding (also called intent redirection) occurs when an application extracts an Intent from user-controlled sources and passes it to component launch methods without proper validation. This vulnerability allows attackers to access private application components, bypass security controls, and manipulate permissions.
This detector identifies dangerous patterns where:
-
Intent extracted via
getParcelableExtra(),parseUri(), or similar methods -
Intent passed directly to
startActivity(),startService(), orsendBroadcast() -
No validation between extraction and forwarding
Research shows over 80% of Android applications contain this vulnerability pattern.
The terms "Intent Forwarding," "Intent Redirection," and "Intent Manipulation" are often used interchangeably in security literature. Please note that Intent Manipulation is an umbrella term used in OWASP Mobile Top 10 (M1: Improper Platform Usage) that encompasses intent-based vulnerabilities, such as Intent Forwarding/Redirection (CWE-940, CWE-926) covered by this detector, and Intent URI Permission Manipulation (CWE-266) covered by kotlin.android_uri_permission_manipulation.
Rationale
Android’s security model relies on component export controls to protect internal functionality. Intent forwarding bypasses these controls by allowing external applications to leverage an exported "proxy" component to reach unexported components.
Attack Vectors:
-
Component Access: Force the app to launch private activities or services not meant to be publicly accessible
-
URI Permission Manipulation: Inject flags like
FLAG_GRANT_PERSISTABLE_URI_PERMISSIONto gain persistent access to content providers -
Data Exfiltration: Access protected files, databases, or credentials through FileProvider exploitation
-
Privilege Escalation: Execute functionality requiring permissions the attacker’s app doesn’t have
Remediation
Component Validation (Recommended)
Validate the destination component before launching:
// SECURE: Validate component destination
val forwardIntent = intent.getParcelableExtra<Intent>("key")
val component = forwardIntent?.resolveActivity(packageManager)
if (component != null &&
component.packageName == packageName &&
component.className == "com.example.SafeActivity") {
startActivity(forwardIntent)
} else {
Log.w(TAG, "Rejected unsafe intent destination")
}
IntentSanitizer (Android 12+)
Use IntentSanitizer to allowlist safe components:
import androidx.core.content.IntentSanitizer
val unsafeIntent = intent.getParcelableExtra<Intent>("forward")
val sanitized = IntentSanitizer.Builder()
.allowComponent("com.example.SafeActivity")
.allowPackage("com.example")
.allowData("com.example")
.allowType("text/plain")
.allowFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.build()
.sanitizeByThrowing(unsafeIntent)
startActivity(sanitized)
Explicit Intents Only
Replace dynamic forwarding with explicit intents:
// SECURE: Create new explicit intent
val safeIntent = Intent(this, TargetActivity::class.java)
safeIntent.putExtra("data", intent.getStringExtra("data"))
startActivity(safeIntent)
Flag Validation
Check for dangerous permission flags:
val forwardIntent = intent.getParcelableExtra<Intent>("intent")
val dangerousFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
if (forwardIntent != null && (forwardIntent.flags and dangerousFlags) != 0) {
Log.w(TAG, "Intent contains dangerous URI permission flags")
return
}
// Additional validation before launching
validateAndStartActivity(forwardIntent)
Avoid Exposing Intent Forwarding
The best solution is to avoid creating proxy components that forward intents:
// VULNERABLE: Proxy pattern
class ProxyActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
val forward = intent.getParcelableExtra<Intent>("forward")
startActivity(forward) // Dangerous!
}
}
// SECURE: Direct implementation
class SafeActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Handle the request directly without forwarding
processRequest(intent.getStringExtra("data"))
}
}
Vulnerable Patterns
Direct Forwarding
// VULNERABLE: No validation
val forwardIntent = intent.getParcelableExtra<Intent>("key")
startActivity(forwardIntent)
Service Redirection
// VULNERABLE: Service forwarding
val extraIntent = intent.getParcelableExtra<Intent>("service")
startService(extraIntent)
Broadcast Redirection
// VULNERABLE: Broadcast forwarding
val broadcastIntent = intent.getParcelableExtra<Intent>("broadcast")
sendBroadcast(broadcastIntent)
References
-
Android Developer: Intent Redirection
-
OWASP MASTG-TEST-0029 : Testing for Sensitive Functionality Exposure Through IPC
-
CWE-940 : Improper Verification of Source of a Communication Channel
-
CWE-926 : Improper Export of Android Application Components