Most security researchers think of mobile apps as black boxes. You install the app, you proxy the traffic, you poke at the API. That’s a reasonable starting point — but it skips an entire attack surface that lives before the first network request is ever made.
The APK itself.
Android Package files are ZIP archives. Every resource the app ships with — compiled code, layout files, image assets, string tables — is bundled inside and distributed to every device that installs it. That includes anything a developer embedded at build time and forgot to remove. Tokens, keys, credentials, internal URLs. If it’s hardcoded, it’s in the package. And if it’s in the package, it’s readable.
Why This Keeps Happening
The pattern is consistent across hundreds of published findings: a developer integrates a third-party service, generates an API key during development, embeds it directly in the app for convenience, ships to production, and never revisits it.
The reasoning is usually that the key is “public-facing anyway” — the Maps API, for example, is designed to be called client-side. What developers often miss is that keys without restrictions are unrestricted by default. A Google Maps API key with no application or API restrictions attached will accept requests from any origin, for any Maps product, billed to the key owner’s account.
That’s the actual risk: not data exfiltration, but financial abuse. An attacker with an unrestricted key can run it against billing-eligible endpoints — static maps, Street View, geocoding, routes — at volume. The bill lands on the app owner.
Setting Up for APK Analysis
The tools you need are all free and open source. The workflow runs on any system with Java installed.
apktool handles decompiling the APK back into readable resources and smali bytecode. jadx goes further, decompiling the Dalvik bytecode into approximate Java source — useful when you need to trace how a value is used, not just where it’s stored. grep and ripgrep do the heavy lifting for searching.
Start by pulling the APK. If the app is on your device:
adb shell pm path com.example.targetapp
adb pull /data/app/com.example.targetapp-1/base.apk ./target.apk
Or download it directly from a third-party APK mirror if you don’t have the device handy. Either way, the package is the same binary that shipped to production.
Decompiling and Searching
With apktool:
apktool d target.apk -o target_decompiled
This produces a directory of decoded resources. The first place to look is resources.arsc — the compiled resource table, which apktool decodes into res/values/strings.xml. This file is where developers store string constants, and it’s where hardcoded credentials appear most often.
cat target_decompiled/res/values/strings.xml | grep -i "key\|token\|secret\|api\|password"
Don’t stop there. Secrets also appear in:
assets/— configuration files, sometimes JSON or YAML with embedded credentialsres/raw/— arbitrary files bundled as raw resources- smali bytecode — hardcoded string literals that never made it into the resource table
AndroidManifest.xml— API keys for services like Firebase, Maps, and Fabric are sometimes declared as<meta-data>elements
For smali, a broad search is faster than reading file by file:
grep -r "AIza\|Bearer\|sk_live\|api_key" target_decompiled/smali/
Each of those prefixes corresponds to a known key format — Google APIs, authorization headers, Stripe live keys. Build your own list based on what services the app is likely to use. Icon sets, analytics providers, CDNs, crash reporters — all of them require credentials, and all of them are candidates.
Validating What You Find
Finding a string that looks like an API key is step one. Confirming it’s valid and unrestricted is step two — and the only way to understand actual impact.
For Google Maps keys specifically, the validation is straightforward. The Static Maps and Street View APIs accept a key parameter and return a billable response if the key is valid and unrestricted:
https://maps.googleapis.com/maps/api/staticmap?center=0,0&zoom=1&size=400x400&key=YOUR_KEY_HERE
A rendered map image means the key is active and unrestricted. A REQUEST_DENIED response means restrictions are in place. That distinction is the difference between a valid finding and a non-issue.
For other key types — Firebase, Stripe, Twilio, AWS — each has its own validation mechanism. Firebase keys can be tested against the REST API. AWS keys can be tested with aws sts get-caller-identity. The principle is the same: don’t report a key without confirming its scope.
What to Look for Beyond Maps
Google Maps keys get the most attention because they’re common and the billing abuse is easy to demonstrate. But they’re far from the only thing worth finding in an APK.
Firebase configuration files (google-services.json is frequently bundled as a raw asset) contain project identifiers and API keys that, combined with misconfigured Firebase security rules, have led to full database read access in real-world findings. Crash reporting keys — Crashlytics, Sentry, Bugsnag — are lower severity on their own but confirm infrastructure details useful for further research. Internal endpoint URLs and staging environment references reveal attack surface that isn’t publicly documented.
The methodology is the same regardless of the service: find the string, understand what service it authenticates to, validate its scope, assess the impact.
Reporting and Remediation
When reporting a hardcoded key finding, the impact statement matters. “Key found in APK” on its own is weak. “Unrestricted Maps API key found in APK, validated against Street View and Static Maps endpoints — key is billable and accepts requests from any origin” is a finding.
The fix on the developer side has two parts. First, the immediate response: rotate or restrict the exposed key. For Google Maps, restriction is straightforward — lock the key to the specific app’s package name and SHA-1 certificate fingerprint, and restrict it to only the APIs it needs. Second, the process change: secrets don’t belong in source code or resource files. Environment variables at build time, or secrets management systems for backend keys, are the correct approach.
A key rotated but re-embedded in the next release fixes nothing.
Takeaway
APK analysis belongs in every mobile security assessment, not as an afterthought but as the first step. The binary that ships to millions of devices contains everything the developer bundled at build time — and developers routinely bundle more than they intend to. The decompile takes minutes. The search takes seconds. What you find can range from informational to directly billable impact depending on what’s there and how it’s configured.