Skip to content
All posts
July 21, 20264 min read

Android App Security: Preventing Common Vulnerabilities

The Android vulnerabilities I see most often in real apps aren't exotic — they're exported components, insecure storage, and sloppy intents. Here's how to prevent the common ones before they ship.

SecurityAndroidVulnerabilitiesBest PracticesMobile Security
Share:

Most Android security incidents aren't clever attacks on novel weaknesses. They're the same handful of avoidable mistakes, shipped over and over. The good news for a solo developer is that preventing the common vulnerabilities is mostly discipline, not deep security expertise. Here are the ones I actively guard against on every app.

Lock Down Exported Components

The most frequent real-world Android leak is an

code
Activity
,
code
Service
, or
code
BroadcastReceiver
that's exported when it shouldn't be. An exported component can be invoked by any other app on the device. If yours performs a sensitive action and trusts whoever called it, that's an open door. The rule is simple: export nothing unless another app genuinely needs to call it, and when you must export something, protect it with a permission and validate the input.

xml
<activity android:name=".InternalActivity" android:exported="false" />

Audit your merged manifest, not just your own file — libraries can add exported components you didn't write.

Never Trust an Incoming Intent

An intent from outside your app is untrusted input. If you read an extra and use it to load a file, navigate, or grant access, an attacker can craft a malicious intent. Validate every value that crosses that boundary, and never use an incoming intent to construct a file path or a privileged action without checking it. The same applies to deep links — a deep link is a URL a stranger can send your app, so treat its parameters as hostile until proven safe.

Store Sensitive Data Encrypted

Plain

code
SharedPreferences
and unencrypted files are readable on a compromised or rooted device. Anything sensitive — tokens, personal data — belongs in encrypted storage backed by the Android Keystore, where the key material lives in hardware the app itself can't extract. The cheapest data to secure is the data you never stored, so I also question whether I need to persist a value at all before deciding how to protect it.

Keep Communication Secure

All network traffic is HTTPS, and I block cleartext explicitly in the network security config so a misconfigured endpoint can't silently downgrade to plain HTTP. For high-value endpoints, certificate pinning raises the bar against man-in-the-middle attacks on hostile networks. Transport security is foundational — if the channel isn't secure, nothing you do on either end matters.

Minimize Permissions and Data

Every permission you request and every field you collect is both an attack surface and a liability you must declare. I request the minimum permissions the feature needs and drop any that a refactor made unnecessary. The same goes for data: collecting less means less to leak, less to secure, and a simpler data safety declaration. Security and privacy reinforce each other here — the leanest app is also the most defensible one.

Make Security Part of the Workflow

The reason these vulnerabilities ship isn't that they're hard to prevent; it's that nobody looks until something goes wrong. I fold the checks into normal work: a credential scan runs before commits so secrets can't sneak into git, I review the manifest's exported components before release, and I treat any new boundary — an intent, a deep link, a stored secret — as a moment to ask the security question while the fix is still cheap. None of this requires being a security researcher. It requires building the habit of asking, at each boundary, what an attacker could do with it, and closing the obvious doors before they ship.

It helps to remember that attackers are economically rational: they go for the easy, high-reward targets, not the hardest ones. Most of the vulnerabilities here are easy wins for an attacker precisely because they're so common, which means closing them moves your app out of the "low effort, decent payoff" bucket that opportunistic attacks target. You don't need to be unbreakable; you need to be enough of a hassle that it's not worth the trouble compared to the next app. That's an achievable bar for a solo developer, and it's reached not through heroics but through the boring consistency of doing these basics on every release, so a vulnerability never quietly slips through while your attention was elsewhere.

Key Takeaways

  • Export components only when another app must call them, protect exported ones with permissions, and audit the merged manifest.
  • Treat incoming intents and deep links as untrusted input; validate every value before acting on it.
  • Store sensitive data in Keystore-backed encrypted storage, and question whether you need to persist it at all.
  • Enforce HTTPS, block cleartext in the network security config, and pin certs for sensitive endpoints.
  • Request the minimum permissions and collect the minimum data — less surface, less liability, simpler declarations.
  • Build the security check into your normal workflow so the common mistakes get caught while fixes are cheap.
Share:
S

Sudarshan Chaudhari

AI Systems Builder / Product Engineer

Bangkok, Thailand

Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.

Stay updated

Get new posts on Android, Kotlin, and solo dev straight to your inbox.

Newsletter preferences

Related Apps

MyFamilyTracker

Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.

Building something? Available for Android dev and QA consulting.

Work with me

Comments — powered by Giscus