aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
  • Programming

Making Sense Of Intent Filters In Android 13

  • aster.cloud
  • July 11, 2022
  • 5 minute read

Before Android 13, when an app registered an exported component in its manifest and added an <intent-filter>, the component could be started by any explicit intent — even those that do not match the intent filter. In some circumstances this can allow other apps to trigger internal-only functionality.

This behavior has been updated in Android 13. Now intents that specify actions and originate from external apps are delivered to an exported component if and only if the intent matches its declared <intent-filter> elements.


Partner with aster.cloud
for your next big idea.
Let us know here.



From our partners:

CITI.IO :: Business. Institutions. Society. Global Political Economy.
CYBERPOGO.COM :: For the Arts, Sciences, and Technology.
DADAHACKS.COM :: Parenting For The Rest Of Us.
ZEDISTA.COM :: Entertainment. Sports. Culture. Escape.
TAKUMAKU.COM :: For The Hearth And Home.
ASTER.CLOUD :: From The Cloud And Beyond.
LIWAIWAI.COM :: Intelligence, Inside and Outside.
GLOBALCLOUDPLATFORMS.COM :: For The World's Computing Needs.
FIREGULAMAN.COM :: For The Fire In The Belly Of The Coder.
ASTERCASTER.COM :: Supra Astra. Beyond The Stars.
BARTDAY.COM :: Prosperity For Everyone.

Counterintuitive

In existing Android versions, there are two ways to deliver an intent to a component (such as an <activity>) where the intent does not match the component’s declared <intent-filter> elements:

  1. Explicit intents: intents with a component name set will always be delivered to the component, as long as the sender has permission.
  2. Intent selectors: when setting a matching intent as a selector of the main intent, the main intent will always be delivered.

Developers expected that intent-filters would impact all intents rather than just a subset. In fact we’ve seen a lot of confusion around intent-filters.

A Review

For each of the following questions, you are presented with the following:

  • The creation of an intent object, which is passed to startActivity() or sendBroadcast().
  • An <intent-filter> element.

Your job is to answer the question: Will the intent match the intent filter?

First, the intent:

// Java
Intent intent = new Intent("foo");
startActivity(intent);

// Kotlin
val intent = Intent(“foo”)
startActivity(intent)

And the intent filter:

<activity android:name=".MyActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="foo" />
    </intent-filter>
</activity>

No!

If an intent does not contain any categories, Android will treat it as if CATEGORY_DEFAULT to all implicit intents passed to startActivity() and startActivityForResult(). Note, this behavior is defined if and only if that intent is used to launch an activity. Intent filters must include CATEGORY_DEFAULT in order to receive implicit activity intents (documentation). Note that this only applies when starting an activity. They do not apply to launching services or sending broadcasts.

Read More  Support Modern Emoji

To correctly match this example the intent filter should be implemented as follows:

<activity android:name=".MyActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="foo" />
+       <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

How about another one?

Intent:

<receiver android:name=".MyReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="foo" />
    </intent-filter>
</receiver>

Filter:

<receiver android:name=".MyReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="foo" />
+       <data android:scheme="https" />
    </intent-filter>
</receiver>

No again!

An intent filter must specify a <data> element to accept intents with data (documentation). To match it should look like this:

<receiver android:name=".MyReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="foo" />
+       <data android:scheme="https" />
    </intent-filter>
</receiver>

One Risk Improved

In the past year we found one particular pitfall that we think we can help with, making intent filters work in a more intuitive way.

Let’s look at it as an example:

Intent:

-Java-
Intent intent = new Intent("bar");
// Setting an explicit component name
intent.setClassName("com.example",
    "com.example.MyActivity");
startActivity(intent);

-Kotlin-
val intent = Intent(“foo”)
intent.setClassName(“com.example”, "com.example.MyActivity")
startActivity(intent)

Filter:

<activity android:name=".MyActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="foo" />
        <category 
            android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

In existing Android versions, yes — the intent does match the filter! This is because explicit intents don’t need to match declared intent filters. When an app declares an exported component in its manifest and adds an <intent-filter>, the component can be started by any intent — even those that do not match the intent filter! This could have caused vulnerabilities in many apps.

Here is an example we’ve discovered in the wild:

Code of victim app:

object MyIntentHandler {
  fun handleIntent(context: Context, intent: Intent) {
    // Handles all intents of the application
  }
}

class InternalReceiver : BroadcastReceiver() {
  override fun onReceive(context: Context, intent: Intent) {
    // Dispatch all actions to centralized handler
    MyIntentHandler.handleIntent(context, intent)
  }
}

class ExternalReceiver : BroadcastReceiver() {
  override fun onReceive(context: Context, intent: Intent) {
    // Dispatch all actions to centralized handler without checks
    MyIntentHandler.handleIntent(context, intent)
  }
}

Components declared in victim’s manifest:

Read More  PyCon 2019 | Design Patterns in Python for the Untrained Eye
<receiver
    android:name=".InternalReceiver"
    android:exported="false" >
  <intent-filter>
    <action android:name="com.example.PRIVATE_INTERNAL_ACTION" />
  </intent-filter>
</receiver>

<receiver
    android:name=".ExternalReceiver"
    android:exported="true" >
  <intent-filter>
    <action android:name="com.example.PUBLIC_EXTERNAL_ACTION_1" />
    <action android:name="com.example.PUBLIC_EXTERNAL_ACTION_2" />
  </intent-filter>
</receiver>

The action com.example.PRIVATE_INTERNAL_ACTION is not supposed to be accessible outside of the application, since the receiver that handles it (InternalReceiver) is not exported. However, due to the fact that ExternalReceiver does not check and guard the incoming action, a malicious actor can do the following to trigger internal functionality:

// Set action to the internal action
val intent = Intent("com.example.PRIVATE_INTERNAL_ACTION")
  
// Set an explicit component name. Before Android 13, this intent
// will always be delivered, even if the action does not match the
// intent filter declared in the manifest.
intent.setClassName("com.example", "com.example.ExternalReceiver")

sendBroadcast(intent)

For apps that target Android 13+ this has now changed. The next section describes these changes.

What’s Changed?

Starting for apps targeting Android 13+ (the intent receiving side), all intents originating from external apps are delivered to an exported component if and only if the intent matches its declared <intent-filter> elements.

One big caveat: If an intent does not specify an action, it passes the intent matching test as long as the filter contains at least one action. This means that you should always handle the case if the incoming intent does not have an action (when intent.getAction() returns null)!

Non-matching intents are blocked. Situations where intent matching is not enforced include the following:

  • Intents delivered to components that don’t declare any intent filters
  • Intents originating within the same app
  • Intents originating from the system and from root.

While this change is great for security reasons — if you were depending on this behavior to make your app interact with another through explicit intents, you may see behavior changes in your app, even if you don’t update to target Android 13.

Read More  Create An App With This Arnold Schwarzenegger-Themed Programming Language

With these changes, the malicious actor in our previous example can no longer trigger internal functionality of our victim application on Android 13, assuming the victim application is updated to target Android 13. However, it is still strongly recommended to update all exported components to check and only accept actions that are allowed to protect your application when running on older Android versions. Our updated example will be like this:

class ExternalReceiver : BroadcastReceiver() {

  private val allowedActions = listOf(
    "com.example.PUBLIC_EXTERNAL_ACTION_1", 
    "com.example.PUBLIC_EXTERNAL_ACTION_2"
  )

  override fun onReceive(context: Context, intent: Intent) {
    // Skip when action is null
    val action = intent.action ?: return
    
    // Only accept actions that are allowed 
    if (!allowedActions.contains(action)) {
      return
    }

    // Dispatch all actions to centralized handler
    MyIntentHandler.handleIntent(context, intent)
  }
}

What should I do?

First, we should note, the enforcement is only enabled if the intent receiving app targets Android 13+. It does NOT affect intents delivered to the same app internally.

Intent sending side

If you are sending explicit intents (intents with an explicit component name set) to another app, ensure that the intent matches the components’ <intent-filter> elements. The matching logic is exactly the same as resolving implicit intents.

When trying to start an activity with a non-matching explicit intent, you will get an immediate ActivityNotFoundException with the message:

Unable to find explicit activity class {component name}; have you declared this activity in your AndroidManifest.xml, or does your intent not match its declared <intent-filter>?

For broadcast receivers and services, there is no obvious signal of failure other than warning logcat messages in the tag “PackageManager”:

Intent does not match component’s intent filter: <intent description>

Access blocked: <component name>

Intent receiving side

Make sure to declare all possible intent filters that your component expects and accepts in AndroidManifest.xml.

Beyond that, if a component only expects explicit intents, consider removing all <intent-filter> elements if no filtering is desired. Components with no intent filters will accept any explicit intent.

Testing

This change is already enabled on Android 13 builds, since Developer Preview 1.

You can toggle this change using the compatibility framework UI in developer options, or by entering the following ADB command in a terminal window:

$ adb shell am compat disable ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS <package>

Remember that this applies to the app receiving the intent; you cannot disable the change for intents that your app sends to other apps.

Going Forward

Because this change can affect developers even before they target 13, it’s important to investigate this change and coordinate an update soon if you use intents to interact with external apps. For more information, check out our docs that describe intents and intent filters.

By Todd Burner
Source Medium


For enquiries, product placements, sponsorships, and collaborations, connect with us at [email protected]. We'd love to hear from you!

Our humans need coffee too! Your support is highly appreciated, thank you!

aster.cloud

Related Topics
  • Android
  • Android 13
  • Intent Filters
  • Medium
You May Also Like
View Post
  • Architecture
  • Data
  • Engineering
  • People
  • Programming
  • Software Engineering
  • Technology
  • Work & Jobs

Predictions: Top 25 Careers Likely In High Demand In The Future

  • June 6, 2023
View Post
  • Programming
  • Software Engineering
  • Technology

Build a Python App to Alert You When Asteroids Are Close to Earth

  • May 22, 2023
View Post
  • Programming

Illuminating Interactions: Visual State In Jetpack Compose

  • May 20, 2023
View Post
  • Computing
  • Data
  • Programming
  • Software
  • Software Engineering

The Top 10 Data Interchange Or Data Exchange Format Used Today

  • May 11, 2023
View Post
  • Architecture
  • Programming
  • Public Cloud

From Receipts To Riches: Save Money W/ Google Cloud & Supermarket Bills – Part 1

  • May 8, 2023
View Post
  • Programming
  • Public Cloud

3 New Ways To Authorize Users To Your Private Workloads On Cloud Run

  • May 4, 2023
View Post
  • Programming
  • Public Cloud

Buffer HTTP Requests With Cloud Tasks

  • May 4, 2023
View Post
  • Programming
  • Public Cloud
  • Software
  • Software Engineering

Learn About Google Cloud’s Updated Renderer For The Maps SDK For Android

  • May 4, 2023

Stay Connected!
LATEST
  • college-of-cardinals-2025 1
    The Definitive Who’s Who of the 2025 Papal Conclave
    • May 7, 2025
  • conclave-poster-black-smoke 2
    The World Is Revalidating Itself
    • May 6, 2025
  • oracle-ibm 3
    IBM and Oracle Expand Partnership to Advance Agentic AI and Hybrid Cloud
    • May 6, 2025
  • 4
    Conclave: How A New Pope Is Chosen
    • April 25, 2025
  • Getting things done makes her feel amazing 5
    Nurturing Minds in the Digital Revolution
    • April 25, 2025
  • 6
    AI is automating our jobs – but values need to change if we are to be liberated by it
    • April 17, 2025
  • 7
    Canonical Releases Ubuntu 25.04 Plucky Puffin
    • April 17, 2025
  • 8
    United States Army Enterprise Cloud Management Agency Expands its Oracle Defense Cloud Services
    • April 15, 2025
  • 9
    Tokyo Electron and IBM Renew Collaboration for Advanced Semiconductor Technology
    • April 2, 2025
  • 10
    IBM Accelerates Momentum in the as a Service Space with Growing Portfolio of Tools Simplifying Infrastructure Management
    • March 27, 2025
about
Hello World!

We are aster.cloud. We’re created by programmers for programmers.

Our site aims to provide guides, programming tips, reviews, and interesting materials for tech people and those who want to learn in general.

We would like to hear from you.

If you have any feedback, enquiries, or sponsorship request, kindly reach out to us at:

[email protected]
Most Popular
  • 1
    Tariffs, Trump, and Other Things That Start With T – They’re Not The Problem, It’s How We Use Them
    • March 25, 2025
  • 2
    IBM contributes key open-source projects to Linux Foundation to advance AI community participation
    • March 22, 2025
  • 3
    Co-op mode: New partners driving the future of gaming with AI
    • March 22, 2025
  • 4
    Mitsubishi Motors Canada Launches AI-Powered “Intelligent Companion” to Transform the 2025 Outlander Buying Experience
    • March 10, 2025
  • PiPiPi 5
    The Unexpected Pi-Fect Deals This March 14
    • March 13, 2025
  • /
  • Technology
  • Tools
  • About
  • Contact Us

Input your search keywords and press Enter.