Skip to content

Android App Security Checklist

Phase 0: Governance, environment, and CI/CD

Enforce CI gates

  • Run static checks on every PR: ktlint / Android Lint, unit/UI tests, dependency audit (Gradle, SBOM).
  • Block release on High/Critical SAST/SCA/DAST findings; zero lint errors on release branches.

Secrets handling

  • No secrets in source, BuildConfig, AndroidManifest.xml, resources, or logs.
  • Use environment/secret manager (e.g., Gradle secrets, cloud KMS); redact secrets in analytics.
  • Rotate keys/tokens periodically and on suspicion of leakage.

Evidence and traceability

  • Archive scan reports, SBOM, build logs, and release notes with each artifact.

Scanning automation

  • Integrate a mobile SAST/DAST/SCA platform in CI/CD to run on each PR and pre‑release and automatically fail gates on High/Critical issues.

Phase 1: Threat modeling, data classification, and inventory

  • Classify data (PII, credentials, tokens, payment) and map collection, processing, storage (SharedPreferences, files, databases, Keystore), and transmission.
  • Identify trust boundaries (device, app sandbox, Keystore, IPC/Binder, WebView, native libraries, backend APIs).
  • Inventory third‑party SDKs; prefer well‑maintained, signed, least‑privilege SDKs; minimize count.

Phase 2: Build and configuration hardening (Gradle + Manifest)

Gradle/Release settings

  • Use release builds with code shrinking/obfuscation (minifyEnabled true, shrinkResources true).
  • Strip debug symbols from shipped APK/AAB.
  • Keep mapping files server‑side.
  • Exclude test/debug libraries from release.
  • Remove development endpoints and feature flags from production builds.

Signing and permissions

  • Protect signing keys (hardware‑backed keystores, restricted access).
  • Use dedicated release signing configs.
  • Declare only necessary permissions in AndroidManifest.xml.
  • Avoid excessive dangerous permissions.

Network security config

  • Use networkSecurityConfig to enforce TLS.
  • Disallow cleartext traffic (android:usesCleartextTraffic="false").
  • Use domain config overrides only when necessary and time‑boxed.

Manifest hygiene

  • Do not set components exported="true" unless strictly required; restrict with permissions when exported.
  • Remove debug flags (android:debuggable="false" in release, no allowBackup="true" unless needed with proper encryption).
  • Provide accurate permission rationale text (in‑app) for all runtime permissions.

Phase 3: Local storage and Keystore security

Keystore usage

  • Store long‑lived keys in Android Keystore with strongest feasible protection (hardware‑backed when available, user auth if UX permits).
  • Use setUserAuthenticationRequired(true) for highly sensitive keys; gate operations with biometrics/lockscreen where appropriate.
  • Delete Keystore‑wrapped secrets on logout or device change.
  • Consider device‑binding for high‑risk tokens.

Files, SharedPreferences, and databases

  • Avoid storing secrets or sensitive PII in plaintext files or SharedPreferences.
  • Encrypt sensitive databases/files (e.g., SQLCipher or equivalent file encryption).
  • Use app‑private storage (MODE_PRIVATE).
  • Apply file protection flags where supported.
  • Ensure backups do not contain unencrypted secrets.

Caches and derived data

  • Avoid persisting PII in caches/temp.
  • Purge caches/temp on logout and as part of backgrounding if appropriate.
  • Do not write secrets to logs or SharedPreferences even temporarily.

Phase 4: Privacy safeguards (UI, clipboard, screenshots)

  • Redact sensitive UI in app switcher screenshots (e.g., use FLAG_SECURE on sensitive Activities/Views).
  • For highly sensitive flows, consider additional masking or separate “secure mode” Activities.
  • Avoid reading clipboard on app launch; never place passwords/long‑lived tokens on the clipboard.

Phase 5: Network security and TLS/pinning

HTTPS/TLS enforcement

  • Enforce HTTPS to trusted hosts; reject invalid certificates/hostnames; disable HTTP fallbacks.
  • Configure strict timeouts, exponential backoff with jitter, and fail closed on TLS errors.

Certificate pinning

  • Prefer SPKI SHA‑256 pins; include at least one backup pin per host.
  • Implement pinning via OkHttp / custom TrustManager or networkSecurityConfig.
  • Validate against MITM and expired/rotated leaf scenarios.
  • Plan safe pin rotation; include telemetry on pin failures.

Cookies and tokens

  • For web flows, use secure, HttpOnly, SameSite cookies.
  • Avoid long‑lived bearer tokens on device.
  • Clear cookies and WebView data after sensitive sessions.

Phase 6: Authentication, authorization, and session

Auth flows

  • Use OAuth2/OIDC with PKCE for public clients; never embed client secrets in the app.
  • Prefer system/browser‑based auth (Chrome Custom Tabs / default browser) over in‑app WebView for login.

Tokens

  • Use short‑lived access tokens.
  • Store refresh tokens only in encrypted storage bound to Keystore keys.
  • Rotate and invalidate tokens on logout, device change, and suspicious activities.
  • Bind sessions to device risk where appropriate.

Authorization

  • Enforce authorization server‑side; treat client checks as advisory only.
  • Test and prevent IDOR/BOLA and privilege escalation across all backend APIs used by the app.

Phase 7: WebView hardening

  • Use WebView only when required; prefer browser for authentication and payment when possible.

Defaults

  • Disable JavaScript unless strictly necessary.
  • If JavaScript is enabled, restrict capabilities and disable setAllowFileAccessFromFileURLs and setAllowUniversalAccessFromFileURLs.
  • Do not enable addJavascriptInterface with objects that expose sensitive methods, especially on API < 17.
  • Enforce navigation allowlists (hosts/paths); block file://, javascript:, and untrusted schemes.
  • Use non‑persistent WebView storage for sensitive sessions where feasible.
  • Clear cookies, cache, and history on logout.

Content security

  • Serve first‑party web content over HTTPS only.
  • Disallow mixed content (MIXED_CONTENT_NEVER_ALLOW).
  • Ensure remote content is integrity‑checked and controlled (no untrusted third‑party scripts unless strictly necessary).

  • Prefer App Links (verified links) for deep linking; validate incoming link origins and parameters.

Custom schemes and intents

  • If custom schemes or implicit intents are used, ensure uniqueness and robust validation of all incoming data.
  • Protect exported Activities/Services/BroadcastReceivers with permissions or explicit intents; avoid overly broad intent filters.
  • Defend against intent spoofing, URL hijacking, and open redirects by checking caller identity and parameters.

Phase 9: Reverse engineering and tamper resilience

Reduce static leakage

  • Remove debug builds, verbose logs, debug menus, and test endpoints from release builds.
  • Obfuscate and shrink code (ProGuard/R8) and resources.
  • Avoid leaving meaningful strings (API keys, secrets) in resources or native libraries.

Environment checks

  • Detect root/hooking/debugger indicators (common root paths, writable system dirs, instrumentation frameworks) and log signals.
  • Respond proportionally (reduced functionality, additional verification, or block) based on risk, while maintaining UX.

Tamper testing

  • Ensure repackaged or re‑signed apps fail integrity checks or server attestation (e.g., safety/attestation APIs).
  • Treat client‑side signals as hints to the backend; never as the sole security control.

Phase 10: Cryptography and randomness

  • Use platform‑provided crypto primitives (Java Cryptography Architecture, Android Keystore); do not build custom algorithms.
  • Use modern AEAD modes like AES‑GCM/ChaCha20‑Poly1305 for authenticated encryption.
  • Use established KDFs (PBKDF2/HKDF) with proper parameters and salts.
  • Generate keys/IVs with a secure RNG (SecureRandom or platform APIs).
  • Never reuse IVs/nonces.
  • Keep keys in Keystore or encrypted at rest.

Phase 11: Permissions, notifications, and identifiers

  • Request minimum permissions, at point‑of‑use, with clear in‑context explanations of value to the user.

Privacy‑related permissions

  • Limit access to location, contacts, camera, microphone, storage, and phone state to strict necessity.
  • Handle denial and revocation gracefully.
  • Avoid dark patterns that pressure users.

Identifiers and tracking

  • Prefer app‑scoped or resettable identifiers; avoid building persistent fingerprinting across apps.
  • Use advertising or analytics IDs only according to platform policies.
  • Never use prohibited hardware identifiers for tracking.

Notifications

  • Minimize sensitive data in notification content.
  • Use generic wording and hide details on lock screen when possible.

Phase 12: Logging, analytics, and crash reporting

  • Use structured logging with severity levels; disable verbose/debug logging in release builds.
  • Redact PII and secrets from logs, analytics events, and crash reports.
  • Aggregate and sample analytics where possible.
  • Ensure symbol/mapping files for obfuscated builds are stored securely server‑side for crash de‑obfuscation.
  • Do not ship symbol/mapping files inside the app.

Phase 13: Testing, DAST, and runtime verification

Traffic interception tests

  • Verify resistance to MITM (invalid certs, hostname mismatch, untrusted CA).
  • Verify that pinning blocks interception where configured.

Runtime inspection

  • Confirm no secrets/PII appear in logs.
  • Verify sensitive data is encrypted at rest.
  • Review WebView behavior at runtime (navigation, JS, storage).
  • Review local storage behavior at runtime (files, SharedPreferences, databases).
  • Validate that Keystore‑backed keys are used where expected.
  • Validate that access controls for Keystore keys behave as designed.

API abuse tests

  • Test rate limiting.
  • Test replay protection.
  • Test pagination bounds.
  • Test for mass assignment.
  • Test error message hygiene for backend APIs.

Dynamic analysis

  • Run mobile DAST while exercising core flows to surface transport misconfigurations, WebView issues, storage leaks, and logging problems.
  • Export evidence from DAST for triage and re‑tests.

Phase 14: SBOM, and evidence

SBOM and dependencies

  • Generate SBOM for all Gradle modules and embedded SDKs.
  • Track CVEs and update dependencies regularly.
  • Monitor dependency health as part of release readiness.
  • Monitor license compliance as part of release readiness.

Evidence bundle

  • Attach scan artifacts to the release record.
  • Attach SBOM to the release record.
  • Attach manifest diffs to the release record.
  • Attach permission and component export lists to the release record.
  • Attach automated/manual test reports to the release record.

Phase 15: Reporting and standards alignment

Report

  • Provide executive summary, scope/methodology, detailed findings with PoCs/evidence, risk ratings, remediation guidance, and re‑test results.

Standards mapping (example)

  • ARCH: Phases 1–2
  • PLATFORM: Phases 2, 7–8, 11
  • STORAGE: Phases 3–4
  • CRYPTO: Phase 10
  • AUTH: Phase 6
  • NETWORK: Phase 5
  • CODE: Phases 2, 9, 12
  • RESILIENCE: Phase 9

Practitioner quick‑reference

  • Manifest/Network: No cleartext traffic in release; strict networkSecurityConfig domains; avoid exporting components without strong justification.
  • Secrets & storage: Use Android Keystore for long‑lived keys; encrypt DB/files; never store secrets in SharedPreferences or logs.
  • Network: HTTPS only; certificate/SPKI pinning with backups for critical endpoints; verify MITM attempts fail.
  • Auth: OIDC + PKCE; short‑lived access tokens; refresh tokens in encrypted storage; server‑side authorization; test IDOR/BOLA.
  • WebView: Prefer browser for auth; if WebView, JS off by default, restrict interfaces, allowlist navigation, non‑persistent store for sensitive flows.
  • Privacy: Use FLAG_SECURE for sensitive screens; avoid clipboard secrets; minimize permissions and provide clear explanations.
  • Release hygiene: Obfuscate and shrink; remove debug logs/menus/test endpoints; validate permissions and exported components each release.