← Back to list

BroadcastReceiver Security: 7 Mistakes Every Android Developer Should Avoid

“Every exported component is a potential entry point. Secure it as if an attacker already knows it exists.” — Android Security Best…

Swatiomar in ProAndroidDev · 2026-07-05 18:44 · 19 claps · 5.7 min read paywalled
#android #android-app-development #kotlin #android-development #androiddev
Open on Medium ↗
Wiki topics: 📱 · Mobile Development

BroadcastReceiver Security: 7 Mistakes Every Android Developer Should Avoid

“Every exported component is a potential entry point. Secure it as if an attacker already knows it exists.” — Android Security Best Practice

A few days ago, while working on an Android app, I had to implement a BroadcastReceiver. Although it wasn't my first time using one, I realized that I had always focused on making it work—not on securing it.

That made me wonder: Can another app trigger my receiver? What if it’s exported? Should I be validating every broadcast?

Those questions led me to explore BroadcastReceiver security in more detail. In this article, I’ll share the most common security mistakes I found and the best practices every Android developer should follow.

Can Another App Trigger Code Inside Your App?

Imagine you’ve built an Android app that performs important operations like syncing user data, logging users out, or processing payments.

Everything works perfectly — until another app installed on the same device sends a fake broadcast that triggers one of those operations. a. No root access. b. No sophisticated hacking tools. Just an exported BroadcastReceiver.

This isn’t a rare edge case. Misconfigured BroadcastReceivers have been responsible for many Android security issues over the years. A small mistake in your AndroidManifest.xml or a missing validation check can expose parts of your app to other applications.

In this article, we’ll explore the most common BroadcastReceiver security mistakes Android developers make and, more importantly, how to avoid them.

What is a BroadcastReceiver?

A BroadcastReceiver is an Android component that listens for broadcast messages sent by the Android system or other applications.

Some common examples include:

  • Battery level changed
  • Network connectivity changed
  • Device boot completed
  • Custom broadcasts between applications

Imagine two apps:

App A

  • Sends a broadcast.

App B

  • Receives the broadcast and performs an action.

For example, App A sends a broadcast:

val intent = Intent("com.example.SYNC_DATA")
sendBroadcast(intent)

App B receives it:

class SyncReceiver : BroadcastReceiver() {
  override fun onReceive(context: Context, intent: Intent) {
        Log.d("Receiver", "Broadcast received")
    }
}
                Normal Broadcast Flow

┌───────────────┐
│     App A     │
│ (Sender App)  │
└───────┬───────┘
        │
        │ sendBroadcast()
        ▼
┌──────────────────────────────┐
│      BroadcastReceiver       │
│      (Receiver App)          │
└──────────────┬───────────────┘
               │
               ▼
      Validate Intent & Extras
               │
               ▼
       Perform Intended Action

Looks simple, right?

But here’s the important question:

Who is allowed to send this broadcast?

If the answer is “any app on the device,” you may have a security problem.

             Vulnerable Receiver

        Legitimate App
              │
              │
              ▼
      ┌────────────────┐
      │ BroadcastReceiver │
      └────────────────┘
              ▲
              │
              │ Fake Broadcast
              │
      Malicious App

Because the receiver is exported,
both apps can trigger it.
          Protected BroadcastReceiver

           Legitimate App
      (Signature Permission)
                │
                │ sendBroadcast()
                ▼
┌──────────────────────────────────────┐
│     BroadcastReceiver                │
│  ✔ Permission Verified               │
│  ✔ Action Validated                  │
│  ✔ Extras Validated                  │
└──────────────────────────────────────┘
                ▲
                │
                │
        Malicious App
                │
                │ Permission Denied 
                ▼
          Broadcast Rejected

Mistake 1: Exporting Your Receiver Without Thinking

One of the most common mistakes is exposing a receiver unnecessarily.

<receiver
    android:name=".SyncReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.SYNC_DATA"/>
    </intent-filter>
</receiver>

This configuration allows any application to send the following broadcast:

val intent = Intent("com.example.SYNC_DATA")
sendBroadcast(intent)

Your receiver will execute even though the broadcast didn’t come from your own application.

If the receiver performs actions like:

  • Starting services
  • Deleting files
  • Logging users out
  • Syncing sensitive data
  • Processing payment-related tasks

another app could trigger those operations unexpectedly.

Better Approach

If your receiver only needs to communicate within your own app, don’t export it.

android:exported="false"

This prevents other applications from accessing the receiver entirely.

Mistake 2: Trusting Every Broadcast

Receiving a broadcast doesn’t mean it’s trustworthy.

Here’s an unsafe example:

override fun onReceive(context: Context, intent: Intent) {
  val userId = intent.getStringExtra("USER_ID")
    deleteUser(userId)
}

A malicious app could simply send:

Intent("com.example.DELETE")
    .putExtra("USER_ID", "100")

Your app might delete user data without any verification.

Better Approach

Always Validate Incoming Data. Check:

  • Intent action
  • Required extras
  • Data format
  • Null values
  • Expected value ranges

Example:

override fun onReceive(context: Context, intent: Intent) {
  if (intent.action != "com.example.DELETE")
        return
    val userId = intent.getStringExtra("USER_ID") ?: return
    if (userId.isBlank())
        return
    deleteUser(userId)
}

Never trust input simply because it arrived through a BroadcastReceiver.

Mistake 3: Not Protecting Your Receiver with Permissions

Suppose you have two applications developed by the same company.

Only App A should be allowed to communicate with App B.

Without permission protection, any installed app can send broadcasts to your receiver.

Define a custom permission:

<permission
    android:name="com.example.permission.SECURE_BROADCAST"
    android:protectionLevel="signature"/>

Protect the receiver:

<receiver
    android:name=".SyncReceiver"
    android:permission="com.example.permission.SECURE_BROADCAST"
    android:exported="true"/>

Now only applications signed with the same signing certificate can communicate with your receiver.

This is one of the safest approaches for enterprise apps and apps developed by the same organization.

Mistake 4: Sending Sensitive Data in Broadcasts

Broadcasts should never carry secrets unless absolutely necessary.

Avoid this:

intent.putExtra("PASSWORD", "mypassword")
intent.putExtra("TOKEN", "abcdef123456")

Even if you think the broadcast is internal today, future changes or misconfigurations could expose that data.

Instead:

  • Pass an ID instead of sensitive information.
  • Retrieve secrets securely inside the receiving app.
  • Store credentials using secure storage such as the Android Keystore.

Mistake 5: Forgetting Android 12 Export Rules

Starting with Android 12 (API 31), every component that has an intent-filter must explicitly declare whether it is exported.

Either:

android:exported="true"

or

android:exported="false"

If you forget to specify this attribute, your application won’t install.

Although this change was introduced for compatibility, it also encourages developers to think carefully before exposing application components.

Mistake 6: Doing Heavy Work Inside onReceive()

The onReceive() method is expected to finish quickly.

This is a bad practice:

override fun onReceive(context: Context, intent: Intent) {
  Thread.sleep(15000)
}

Long-running work can cause:

  • ANRs (Application Not Responding)
  • Poor user experience
  • The system terminating your process

Instead, schedule background work using WorkManager.

override fun onReceive(context: Context, intent: Intent) {
  val work = OneTimeWorkRequestBuilder<SyncWorker>()
        .build()
    WorkManager.getInstance(context)
        .enqueue(work)
}

For long-running tasks, consider:

  • WorkManager
  • Foreground Service (only when appropriate)

Keep onReceive() lightweight and return as quickly as possible.

Mistake 7: Using Generic Action Names

Generic action names can easily conflict with broadcasts from other applications.

Avoid names like:

SYNC
UPDATE
START

Instead, use unique, namespace action strings:

com.company.app.ACTION_SYNC
com.company.app.ACTION_LOGIN

This reduces accidental collisions and makes your intent actions self-explanatory.

Sending a Secure Broadcast

A secure sender should target only the intended application and require the proper permission.

val intent = Intent("com.company.app.ACTION_SYNC")
intent.setPackage("com.company.receiver")
sendBroadcast(
    intent,
    "com.company.permission.SECURE_BROADCAST"
)

This provides multiple layers of protection:

  • Only the intended application receives the broadcast.
  • The required permission is enforced.
  • Other applications cannot easily misuse the receiver.

Testing Your Receiver with ADB

Before shipping your application, verify that your receiver behaves as expected.

You can send a broadcast manually:

adb shell am broadcast \
-a com.company.app.ACTION_SYNC

If your receiver is protected with a signature permission, this command should fail when executed by an unauthorized source.

Testing with ADB is a simple way to confirm that your security configuration is working correctly.

            Secure Broadcast Flow

 Sender App
      │
      │
      ▼
 Set Package
      │
      ▼
 Signature Permission
      │
      ▼
 BroadcastReceiver
      │
      ▼
 Validate Action
      │
      ▼
 Validate Extras
      │
      ▼
 Start WorkManager
      │
      ▼
 Business Logic

BroadcastReceiver Security Checklist

a. Keep receivers non-exported unless another app genuinely needs access. b. Validate every incoming intent and its extras. c. Protect exported receivers with custom signature permissions. d. Never send passwords, tokens, or sensitive information through broadcasts. e. Use unique action names. f. Keep onReceive() lightweight. g. Test your receivers using ADB. h. Follow Android 12+ exported component requirements.

Final Thoughts

A BroadcastReceiver is like a door into your application.

Every exported receiver is a door you’re intentionally leaving open for someone else to knock on.

Before exposing a receiver, ask yourself:

  • Does another application really need access?
  • Can this receiver remain private?
  • Should it require a signature permission?
  • What happens if a malicious app sends this broadcast?

Thinking about these questions during development can prevent serious security vulnerabilities later.

A few extra minutes spent securing your BroadcastReceivers today can save hours of debugging tomorrow — and, more importantly, help protect your users and their data.

This article covered what to avoid when using BroadcastReceivers.

If you’d like the next article to cover how BroadcastReceiver actually works internally, including the complete flow through Android’s framework and system services, let me know in the comments. If enough people are interested, I’ll publish a detailed breakdown.

🙌 Thanks for Reading!

If you enjoyed this post or learned something new, I’d love your support:

👍 Clap (up to 50 times!) to help more devs discover it 🔁 Share it with your community 👀 Follow me for more deep dives, breakdowns, and behind-the-scenes insights

💬 Got questions or want to go deeper? 📬 Have a topic you want me to cover? Comment below or reach out to me on LinkedIn — I’d love to hear your suggestions!

Until next time — stay curious, keep building, and Happy coding! 💻✨


메타데이터
post_id
7eeb8439b986
slug
broadcastreceiver-security-7-mistakes-every-android-developer-should-avoid-7eeb8439b986
url
https://proandroiddev.com/broadcastreceiver-security-7-mistakes-every-android-developer-should-avoid-7eeb8439b986
canonical_url
https://proandroiddev.com/broadcastreceiver-security-7-mistakes-every-android-developer-should-avoid-7eeb8439b986
author_url
https://medium.com/@swatiomar09
status
ok
fetched_at
2026-07-08 19:15:55