đŸ›Ąïž Application Security CheatSheet

Android Static Analysis

How to use this cheat sheet

This page is built as a working checklist you can keep open while reviewing an APK. It assumes you already know AppSec (web/API or mobile) and want an assessment-grade static workflow: what to extract, what to flag in the manifest, what grep patterns reliably find real bugs, and what to verify in code before calling it a finding.

Static analysis should answer three questions quickly: (1) what can be reached from outside, (2) what inputs control privileged actions/data, and (3) what protections are real vs assumed.

Tooling setup (minimal, practical)

Recommended baseline tools:

Sanity check versions (optional):

apktool --version
jadx --version
rg --version

APK intake and workspace (repeatable)

Create a clean workspace per target:

APP=app
APK=$APP.apk
mkdir -p runs/$APP
cp "$APK" runs/$APP/
cd runs/$APP

Quick metadata (package name, version, SDKs):

aapt dump badging "$APK" | sed -n '1,40p'

Signature check (release vs debug, key rotation clues):

apksigner verify --print-certs "$APK"
# or:
keytool -printcert -jarfile "$APK" | sed -n '1,80p'

Decode + decompile (two outputs, two purposes)

Decode resources/manifest (best for manifest + XML configs):

apktool d -f "$APK" -o out

Decompile code (best for logic, routing, trust assumptions):

jadx "$APK" -d jadx-out

Use out/AndroidManifest.xml for the canonical decoded manifest (apktool output), and jadx-out/ for code-level verification.

Manifest triage: the high-signal checklist

1) App-wide flags that commonly matter

rg -n "android:debuggable|android:allowBackup|android:usesCleartextTraffic|android:networkSecurityConfig|android:fullBackupContent|android:backupAgent" out/AndroidManifest.xml

2) Exported components and entry points

rg -n "android:exported=\"true\"" out/AndroidManifest.xml
rg -n "<activity|<service|<receiver|<provider" out/AndroidManifest.xml

For each exported component, capture:

3) Intent-filters and deep link surfaces

rg -n "<intent-filter|android.intent.action.VIEW|android.intent.category.BROWSABLE|android.intent.category.DEFAULT" out/AndroidManifest.xml
rg -n "<data\s|android:scheme=|android:host=|android:path=|android:pathPrefix=|android:pathPattern=" out/AndroidManifest.xml

4) Permissions model (declared vs enforced)

rg -n "<permission\b|protectionLevel|signature|dangerous|normal" out/AndroidManifest.xml
rg -n "android:permission=\"" out/AndroidManifest.xml

Common mistake: components “protected” by a normal/dangerous permission for a sensitive capability. If it’s truly internal IPC, signature-level permissions or non-exported components are the usual baseline.

5) Content Providers: authorities, permissions, and grants

rg -n "<provider\b|authorities=|grantUriPermissions=|exported=|readPermission=|writePermission=|permission=" out/AndroidManifest.xml
rg -n "FileProvider|androidx.core.content.FileProvider" out/AndroidManifest.xml

6) Queries (Android 11+ package visibility)

rg -n "<queries\b|<package\b|<intent\b" out/AndroidManifest.xml

7) Task/launch quirks (flow confusion indicators)

rg -n "launchMode=|taskAffinity=|allowTaskReparenting=|excludeFromRecents=|clearTaskOnLaunch=|alwaysRetainTaskState=" out/AndroidManifest.xml

Code triage: fast entry-point discovery patterns

These searches are designed to quickly locate where untrusted input is parsed and where privileged actions occur.

1) Activities: intent data + extras parsing

rg -n "getIntent\(|intent\.|getStringExtra\(|getIntExtra\(|getBooleanExtra\(|getParcelableExtra\(|getSerializableExtra\(" jadx-out
rg -n "getData\(|getDataString\(|Uri\.parse\(|getQueryParameter\(" jadx-out

2) Services: onStartCommand + binder

rg -n "onStartCommand\(|startForeground\(|startForegroundService\(|startService\(" jadx-out
rg -n "onBind\(|IBinder|\.Stub\b|AIDL|Binder\.getCallingUid\(|getCallingUid\(" jadx-out

3) Broadcast Receivers: actions + extras

rg -n "class\s+\w+Receiver\b|extends\s+BroadcastReceiver|onReceive\(" jadx-out
rg -n "sendBroadcast\(|sendOrderedBroadcast\(|registerReceiver\(" jadx-out

4) Content Providers: query/insert/update/delete/openFile

rg -n "extends\s+ContentProvider|onCreate\(|query\(|insert\(|update\(|delete\(|openFile\(|openAssetFile\(" jadx-out
rg -n "ContentResolver\.query\(|ContentResolver\.insert\(|ContentResolver\.update\(|ContentResolver\.delete\(" jadx-out

5) Central routers / dispatchers (high ROI)

rg -n "Router|Dispatcher|DeepLink|Navigation|Navigator|Route|IntentHandler" jadx-out
rg -n "\b(target|next|screen|destination|redirect|url|uri|deeplink)\b" jadx-out

Security-sensitive sinks (what to follow after you find input parsing)

When you find a place that reads extras/URI/binder params, follow it to the first meaningful sink. The sink determines exploitability and severity.

Network sinks

rg -n "OkHttpClient|Request\.Builder\(|Retrofit|HttpUrl|URLConnection|WebViewClient" jadx-out

File/storage sinks

rg -n "SharedPreferences|getSharedPreferences\(|MODE_WORLD_READABLE|openFileOutput\(|File\(|FileOutputStream\(|getExternalFilesDir\(|Environment\.getExternalStorage" jadx-out

IPC sinks

rg -n "PendingIntent\.|getActivity\(|getService\(|getBroadcast\(|FLAG_IMMUTABLE|FLAG_MUTABLE" jadx-out
rg -n "startActivity\(|startService\(|bindService\(|setResult\(|setResultExtras\(|setResultData\(" jadx-out

WebView sinks (frequent real findings)

rg -n "WebView\b|setJavaScriptEnabled\(|addJavascriptInterface\(|setAllowFileAccess\(|setAllowUniversalAccessFromFileURLs\(|loadUrl\(|loadDataWithBaseURL\(" jadx-out

Crypto / key material signals (triage, not theory)

rg -n "Cipher\.getInstance\(|SecretKeySpec\(|MessageDigest\(|Mac\.getInstance\(|Base64\.|KeyStore\b|AndroidKeyStore" jadx-out

Logging / telemetry leaks (common in mobile)

rg -n "\bLog\.(d|i|w|e|v)\(|Timber\.|println\(" jadx-out

Component-by-component static checklist (what to confirm before reporting)

Activities (exported / deep link)

Services (started / bound)

Broadcast Receivers

Content Providers

Grep packs (copy/paste bundles)

Manifest: exported + deep links + permissions

rg -n "android:exported=\"true\"|<intent-filter|BROWSABLE|action\.VIEW|android:scheme=|android:host=|android:path|android:permission=|<permission\b|protectionLevel|grantUriPermissions|authorities=" out/AndroidManifest.xml

Entry parsing (extras/URI) + routing keywords

rg -n "getStringExtra\(|getIntExtra\(|getBooleanExtra\(|getParcelableExtra\(|getSerializableExtra\(|getData\(|getDataString\(|getQueryParameter\(|Uri\.parse\(" jadx-out
rg -n "\b(next|target|screen|route|redirect|url|uri|deeplink|destination)\b" jadx-out

IPC + permission enforcement signals

rg -n "onBind\(|\.Stub\b|AIDL|Binder\.getCallingUid\(|getCallingUid\(|enforceCallingPermission\(|checkCallingPermission\(" jadx-out
rg -n "PendingIntent\.|FLAG_IMMUTABLE|FLAG_MUTABLE|sendBroadcast\(|sendOrderedBroadcast\(|registerReceiver\(" jadx-out

Storage + secrets + logging

rg -n "SharedPreferences|getSharedPreferences\(|openFileOutput\(|MODE_WORLD_|getExternalFilesDir\(|Environment\.getExternalStorage|KeyStore\b|AndroidKeyStore|Base64\.|Cipher\.getInstance\(|SecretKeySpec\(|\bLog\." jadx-out

WebView risk pack

rg -n "WebView\b|addJavascriptInterface\(|setJavaScriptEnabled\(|setAllowFileAccess\(|setAllowUniversalAccessFromFileURLs\(|loadUrl\(|loadDataWithBaseURL\(" jadx-out

These packs are triage-oriented: they tell you where to look. Severity depends on reachable surface and what the code does with the input.

Interview questions & answers (Easy → Medium → Hard → Senior)

Easy

  1. What’s your first step when you receive an APK for assessment?

    I build an attack-surface map: decode the manifest, enumerate exported components and intent-filters, then identify where intents/extras/URIs/binder params are parsed and what privileged actions they control.

  2. Why is AndroidManifest.xml high-signal?

    It declares externally reachable entry points (exported components, deep links), permission gates, and app-wide security posture flags (backup, cleartext, network security config).

Medium

  1. How do you prioritize static review in a large app?

    Exported + parameter-driven entry points first: Activities with BROWSABLE filters, receivers with custom actions, services reading extras, and any binder interfaces. Then I follow input parsing to network/file/IPC sinks.

  2. What’s a common false positive in static analysis?

    Flagging a scary sink without proving reachability. Static triage must connect: entry point → attacker-controlled input → privileged sink, and validate that any “permission checks” are real and enforceable.

Hard

  1. How do you validate authorization for binder methods statically?

    I check whether the service is exported and whether binding is permission-gated. Then in code I look for caller identity checks (getCallingUid()), enforcement APIs (enforceCallingPermission), and method-level authorization based on user/session context.

  2. What static signals suggest flow-confusion risks?

    Broad deep link filters (generic paths), router Activities using next/target/url, and task/launch flags like custom taskAffinity or non-standard launchMode. Then I verify whether post-login intent reuse is sanitized.

Senior

  1. What does “static analysis done well” look like in a report?

    It’s not a dump of grep hits. It’s a chain: the component is reachable (manifest evidence), the app trusts a parameter (code evidence), the parameter controls a privileged action/data access (sink evidence), and the fix is explicit (reduce export, tighten permissions, add caller/session binding, allowlist inputs).

  2. How do you avoid missing hidden entry points?

    I treat exported components like public endpoints and search for centralized routing/dispatch, intent builders, and IPC glue. Those are where apps accidentally expose privileged actions under “helper” code.

← Back: Mobile Security Next: Android Activities →