DEV Community

boryanz
boryanz

Posted on • Edited on

OnNewIntent() in Android

What is onNewIntent, issues with it and how to use it properly without sacrificing security?

I've been working on Android development since 2021, and one method that caught my eye these days was onNewIntent().

Let me explain what it is, why it can be dangerous, and how to use it safely.

What is onNewIntent?

onNewIntent() gets called when your activity is already running and a new intent tries to start it. Instead of creating a new instance, Android delivers the new intent to your existing activity through this method.

Here's a basic example:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        handleIntent(intent)
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        intent?.let { handleIntent(it) }
    }

    private fun handleIntent(intent: Intent) {
        // Process the intent data
        val data = intent.getStringExtra("user_data")
        // Do something with the data
    }
}
Enter fullscreen mode Exit fullscreen mode

This happens when your activity has launch modes like singleTop, singleTask, or singleInstance in the manifest.

The Security Problem

Here's where things get tricky. Other apps can send intents to your activity if it's exported or has intent filters. And if you're not careful, they can pass malicious data.

I've seen developers do this:

override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)

    // DON'T DO THIS - Direct access without validation
    val userId = intent?.getStringExtra("user_id")
    val accountData = intent?.getParcelableExtra<Account>("account")

    // Directly using the data without checks
    loadUserProfile(userId!!)
    processAccount(accountData!!)
}
Enter fullscreen mode Exit fullscreen mode

This is dangerous because any app can craft an intent with malicious data and send it to your activity.

Common Attack Scenarios

Data Injection: Malicious apps can pass harmful strings that might break your app or cause crashes.

Intent Spoofing: Apps can pretend to be legitimate sources and pass fake data.

State Manipulation: Attackers might try to manipulate your app's state by sending unexpected intents.

How to Use onNewIntent Safely

Here's how I handle onNewIntent() securely:

class SecureActivity : AppCompatActivity() {

    private companion object {
        const val EXPECTED_ACTION = "com.yourapp.SECURE_ACTION"
        const val TRUSTED_PACKAGE = "com.yourapp.trusted"
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        intent?.let { 
            if (isIntentSafe(it)) {
                handleSecureIntent(it)
            } else {
                Log.w("SecureActivity", "Rejected unsafe intent")
            }
        }
    }

    private fun isIntentSafe(intent: Intent): Boolean {
        // Check the action
        if (intent.action != EXPECTED_ACTION) {
            return false
        }

        // Verify the calling package if needed
        val callingPackage = callingActivity?.packageName
        if (callingPackage != null && callingPackage != TRUSTED_PACKAGE) {
            return false
        }

        // Validate data types and ranges
        val userId = intent.getStringExtra("user_id")
        if (userId.isNullOrBlank() || !isValidUserId(userId)) {
            return false
        }

        return true
    }

    private fun handleSecureIntent(intent: Intent) {
        val userId = intent.getStringExtra("user_id")
        // Safe to use now
        userId?.let { loadUserProfile(it) }
    }

    private fun isValidUserId(userId: String): Boolean {
        // Your validation logic here
        return userId.matches(Regex("^[a-zA-Z0-9_-]+$")) && userId.length <= 50
    }
}
Enter fullscreen mode Exit fullscreen mode

Best Practices

Always validate: Never trust data from intents without validation.
Use explicit intents: When possible, use explicit intents instead of implicit ones.
Limit exported activities: Only export activities that really need to be accessible from other apps.

// In AndroidManifest.xml
<activity
    android:name=".MainActivity"
    android:exported="false"  // This prevents other apps from starting it
    android:launchMode="singleTop" />
Enter fullscreen mode Exit fullscreen mode

Check calling activity: Use callingActivity to verify who's sending the intent.
Sanitize data: Clean and validate all incoming data before processing.

When to Use Different Launch Modes

  • singleTop: Use when you want to avoid creating duplicate activities on top of the stack
  • singleTask: Use for main activities that should have only one instance
  • singleInstance: Use rarely, only for special cases like phone dialer

Each of these will trigger onNewIntent() under certain conditions.

Real-World Example

I once worked on a banking app where we had to handle deep links. The initial implementation was vulnerable because it trusted all incoming intents. We fixed it by:

  1. Validating the deep link format
  2. Checking if the user was authenticated
  3. Sanitizing all parameters
  4. Using a whitelist of allowed actions
private fun handleDeepLink(intent: Intent) {
    val uri = intent.data ?: return

    // Validate the URI scheme and host
    if (uri.scheme != "bankapp" || uri.host != "secure") {
        return
    }

    // Check authentication first
    if (!userManager.isAuthenticated()) {
        redirectToLogin()
        return
    }

    // Process only allowed paths
    when (uri.path) {
        "/transfer" -> handleTransfer(uri)
        "/balance" -> showBalance()
        else -> showError("Invalid deep link")
    }
}
Enter fullscreen mode Exit fullscreen mode

Takeaway

onNewIntent() is useful but comes with security risks. Always validate incoming data, limit activity exposure, and never trust external intents blindly.
The key is treating every intent as potentially malicious until proven otherwise. It might seem paranoid, but it's better than dealing with security vulnerabilities later.
And remember, security isn't just about preventing crashes. It's about protecting your users' data and maintaining trust in your app.

Top comments (0)