Join our Newsletter — 33% off our NHI Course
Home› Guides› Android App Security Guide: Storage, Keys, Network Security…
Guide Application Security

Android App Security Guide: Storage, Keys, Network Security and Play Integrity

PDF for newsletter subscribers · free to read online

← All guides
By Lalit Choda, NHI Mgmt Group Updated 24 October 2026 16 min read
On this page

Most Android app compromises come from settings the developer turned off or never set: an exported component, a debug trust anchor in a release build, a token in plain SharedPreferences, or an API key compiled into the APK. Android gives app teams strong primitives (Keystore with TEE and StrongBox, Network Security Configuration, Play Integrity, Credential Manager), but each has defaults, version cut-offs and server-side duties that are easy to get wrong. This guide is the Android-specific companion to the cross-platform Mobile App Security Guide: it gives the manifest attributes, API names, API levels and verification steps an Android engineer needs, plus a rollout plan, metrics and failure patterns. It is written for Android developers, mobile security engineers and the application security teams who set release gates for them. For test methods see the Mobile App Security Testing Guide.

Key takeaways

  • Keys belong in Android Keystore, not in files. Keystore key material never enters the app process, and it can be bound to the TEE or StrongBox. The Jetpack security-crypto library (EncryptedSharedPreferences) was deprecated in April 2025 in favour of direct Keystore use.
  • Declare every component's exposure. Since Android 12 (API 31) an activity, service or receiver with an intent filter must declare android:exported or the app will not install. Default to false and protect the rest with signature permissions.
  • Network Security Configuration is the TLS policy file. Cleartext is off by default from API 28, debug trust anchors only apply when the build is debuggable, and pins need a backup pin and a planned expiry.
  • Play Integrity is a server-side signal. SafetyNet Attestation was turned down in January 2025. Decide on the verdict on your backend, bind it to the request, and never trust a check the app performs on itself.
  • The APK is public. Anything compiled in, including API keys and cloud credentials, can be extracted. Use attestation plus a backend token exchange so the app holds only short-lived, device-bound credentials.

The Android security model in practice

Android runs each app under its own Linux UID in a sandbox, so files in internal storage are private to the app by default. Android's security tips describe this default as sufficient for most applications. Everything outside the sandbox is a decision the developer makes: what to export over IPC, what to put in external storage or backups, which certificate authorities to trust, and what to log. The platform has also tightened defaults over time, so the targetSdkVersion you build against changes your security posture.

API levelChange that matters for securityWhat to check
21 (Android 5.0)Implicit intents passed to bindService() throw an exceptionAll service binding uses explicit intents
24 to 27Default Network Security Configuration trusts only system CAs (user-added CAs were trusted by default only up to API 23)No <certificates src="user"/> in release config
28 (Android 9)Cleartext traffic disabled by default; StrongBox KeyMint available on supporting devices; end-to-end encrypted backup when a lock screen is setNo cleartextTrafficPermitted="true" in base-config
29 (Android 10)KeyInfo.getSecurityLevel() reports TRUSTED_ENVIRONMENT or STRONGBOXKeys report a hardware security level
31 (Android 12)Explicit android:exported required for components with intent filters; PendingIntent mutability must be declared; dataExtractionRules replace fullBackupContent; adb backup excludes app dataLint clean for UnspecifiedImmutableFlag; both backup rule files present
Android 16 launch devicesKey attestation uses Remote Key Provisioning only, phasing out factory keysServer attestation verifier handles RKP chains

Storing data and keys: Keystore, TEE and StrongBox

The Android Keystore system performs cryptographic operations in a system process, so an attacker who compromises the app process can use its keys but cannot extract them. Where the device's secure hardware supports the algorithm, key material is bound to the Trusted Execution Environment (TEE) or a Secure Element and never leaves it.

  • Generate keys in Keystore: use KeyPairGenerator or KeyGenerator with the "AndroidKeyStore" provider and a KeyGenParameterSpec that fixes purposes, digests, padding and block modes. These authorisations cannot be changed after creation.
  • Check where the key lives: on API 29 and higher, KeyInfo.getSecurityLevel() should return TRUSTED_ENVIRONMENT or STRONGBOX; on API 28 and lower use isInsideSecurityHardware().
  • Use StrongBox selectively: check FEATURE_STRONGBOX_KEYSTORE, call setIsStrongBoxBacked(true), and catch StrongBoxUnavailableException to fall back to the TEE. StrongBox supports RSA 2048, AES 128 and 256, ECDSA and ECDH on P-256, HMAC-SHA256 and Triple DES. Android's own documentation says it is slower and not necessary for most apps; reserve it for high-value signing keys.
  • Bind keys to the user: setUserAuthenticationParameters() supports a time-based window or per-operation authorisation with AUTH_BIOMETRIC_STRONG, AUTH_DEVICE_CREDENTIAL or both, triggered through BiometricPrompt. Biometric-only keys are invalidated when a new biometric is enrolled unless you pass false to setInvalidatedByBiometricEnrollment(); for banking-grade apps keep the default.
  • Plan the EncryptedSharedPreferences migration: androidx.security:security-crypto deprecated all APIs in 1.1.0-alpha07 (9 April 2025) in favour of platform APIs and direct use of Android Keystore. Existing data should be decrypted and re-encrypted with a Keystore-held AES-GCM key in a controlled app update.
  • Keep data out of shared places: never use the deprecated MODE_WORLD_READABLE or MODE_WORLD_WRITEABLE, keep sensitive data out of external storage, and verify any code loaded from external storage cryptographically before use.
val spec = KeyGenParameterSpec.Builder("session-signing",
        KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY)
    .setDigests(KeyProperties.DIGEST_SHA256)
    .setAttestationChallenge(serverNonce)   // server-issued, single use
    .setIsStrongBoxBacked(hasStrongBox)     // fall back on StrongBoxUnavailableException
    .build()

Backups and data extraction

Auto Backup is on by default. For apps targeting API 31 and higher, set android:dataExtractionRules on <application> with separate <cloud-backup> and <device-transfer> sections; if device transfer rules are absent, all app data moves during device-to-device migration. Keep a fullBackupContent file as well for devices on Android 11 and lower. Exclude token stores and databases holding personal data, or require encryption with disableIfNoEncryptionCapabilities="true" (the Android 12 name for clientSideEncryption). Android's backup guidance names home-grown "export" features that write app data to shared directories as the main risk.

Exported components, intents and WebViews

IPC is where Android apps most often expose functionality to other apps on the same device. Treat every exported component as a public API.

Component or APIRiskSafe setting
Activity, service, receiver with intent filterOther apps can launch it or send it dataandroid:exported="false" unless it is the launcher or a deliberate entry point (required to be explicit from API 31)
ContentProviderOther apps read or write the app's dataandroid:exported="false"; if shared with your own apps, a permission with android:protectionLevel="signature"
Service IPC callsCaller lacks the right to the operationDeclarative manifest permissions, or checkCallingPermission() in the handler
BroadcastsAny app receives sensitive broadcastsExplicit intents, or sendBroadcast with a non-null receiver permission
PendingIntentA receiving app modifies the wrapped intentDeclare mutability (FLAG_IMMUTABLE by default) and fix the UnspecifiedImmutableFlag lint warning
WebViewUntrusted script calls native code through a bridgeLeave JavaScript off unless needed; use addJavascriptInterface() only for fully trusted, ideally bundled, content; clearCache() after sensitive sessions
LogsApps holding READ_LOGS read PII and tokensNo PII or tokens in logs; strip verbose logging from release builds
  • Validate everything received: intent filters are not a security boundary. Validate intent extras, deep link parameters and provider queries as untrusted input, and use the Android 12 StrictMode check for unsafe intent launches during testing.
  • Use explicit intents internally: name the target component for anything sensitive, and keep internal-only IPC unexported even in multi-process apps that share a UID.

Network Security Configuration and TLS

The android:networkSecurityConfig attribute on <application> points to an XML file, usually res/xml/network_security_config.xml. It holds one optional <base-config>, any number of <domain-config> elements (the longest matching domain rule wins) and one optional <debug-overrides>.

<network-security-config>
  <base-config cleartextTrafficPermitted="false">
    <trust-anchors><certificates src="system"/></trust-anchors>
  </base-config>
  <domain-config>
    <domain includeSubdomains="true">api.example.com</domain>
    <pin-set expiration="2027-06-30">
      <pin digest="SHA-256">[primary SPKI hash]</pin>
      <pin digest="SHA-256">[backup SPKI hash]</pin>
    </pin-set>
  </domain-config>
  <debug-overrides>
    <trust-anchors><certificates src="@raw/debug_cas"/></trust-anchors>
  </debug-overrides>
</network-security-config>
  • Test CAs go in debug-overrides only: the section is ignored when android:debuggable is false, so an interception proxy CA cannot leak into release. Never add src="user" to a release base-config.
  • Pins need a backup and an expiry policy: pin digests are SHA-256 hashes of the SubjectPublicKeyInfo. Ship at least two. After the expiration date pinning is disabled, which avoids bricking old installs but also lets an attacker with a trusted CA bypass pins on stale versions; pair expiry with a forced-update policy.
  • Do not hand-roll TLS: use HttpsURLConnection or a maintained client. Android's security tips warn that raw SSLSocket does not verify hostnames, and custom TrustManager or HostnameVerifier classes that accept everything remain a top test finding.

Play Integrity and key attestation

Play Integrity replaced SafetyNet Attestation, which Google deprecated in 2022 and fully turned down in January 2025; the old attest call now always fails. Play Integrity returns an encrypted verdict that your server must decode and check.

Verdict fieldExpected valueWhat it tells you
requestDetailsMatching requestHash (standard) or nonce (classic)The verdict belongs to this request and is not a replay
appIntegrity.appRecognitionVerdictPLAY_RECOGNIZEDSigning certificate recognised by Play, binary untampered
accountDetails.appLicensingVerdictLICENSEDUser installed or updated the app from Google Play
deviceIntegrity labelsMEETS_STRONG_INTEGRITY, MEETS_DEVICE_INTEGRITY, MEETS_BASIC_INTEGRITYTiered device trust; strong requires hardware-backed signals and a recent security patch on Android 13 and higher
Optional: appAccessRiskVerdict, playProtectVerdict, recentDeviceActivityPolicy dependentCapture or overlay apps, known malware, request bursts from one device
  • Choose the request type: standard requests need a warm-up, return in a few hundred milliseconds and bind the verdict with requestHash; classic requests take seconds and use a server nonce. Use standard requests for frequent checks and classic for rare high-value actions. Google advises against caching verdicts.
  • Grade the response: the documentation recommends a range of outcomes (allow, allow with limits, allow after challenge, deny) rather than a binary block, and handling failures with the remediation dialog.
  • Watch the quota: the default is 10,000 requests per day across all installs, so call it at sign-in, enrolment and sensitive transactions rather than on every API call.
  • Use key attestation for device-bound keys: generate a Keystore key with setAttestationChallenge(), send the certificate chain to your server, verify it chains to a Google attestation root (published at android.googleapis.com/attestation/root, with a new root signing from 1 February 2026), check attestationSecurityLevel and the revocation list, and read only the first attestation extension nearest the root. Google recommends its key attestation verification library over custom parsers, and never validating on the device itself.

Where identity fits: API keys, tokens and the app as a client

An Android app is a non-human client with no way to keep a secret. Symantec's research on mobile apps with hard-coded AWS keys found 1,859 Android and iOS apps carrying cloud credentials, 53% of them reusing tokens that came from shared libraries and SDKs, so one vendor's mistake was copied into many apps.

  1. Ship no backend secrets: cloud keys, payment secret keys and AI provider keys stay on your servers in a vault. See the Secrets Management Guide.
  2. Attest, then exchange: the app sends a Play Integrity verdict (and optionally a key attestation chain) to your backend, which issues a short-lived access token bound to a Keystore key held on the device. Calls are signed with that key, so a copied token is useless elsewhere.
  3. Restrict unavoidable client keys: mapping or push keys that must ship should be restricted by package name and signing certificate fingerprint and limited to the APIs they need. See the API Key Management Guide.
  4. Sign users in with Credential Manager: the Jetpack androidx.credentials API unifies passkeys, passwords and Sign in with Google, and replaces the legacy Google Sign-In, One Tap and Smart Lock for Passwords APIs. See the Passwordless and Passkeys Guide.
  5. Protect the signing identity: the upload and app signing keys, and the CI account that publishes to Play, can push code to every user. Keep them in a managed signing service or HSM with named owners. See the Code Signing Security Guide.

Developer verification

Google is adding developer identity verification for apps installed on certified Android devices. Its developer verification page lists APIs, limited distribution accounts and an advanced flow for power users from August 2026, enforcement from 30 September 2026 for installs on Android 7 and higher in Brazil, Indonesia, Singapore and Thailand, and global expansion in 2027. Google Play registers most Play apps automatically; teams distributing outside Play register through the Android Developer Console. Check the current page before planning, as the timeline has been updated during 2026.

Choosing controls by app risk

ControlLow-risk app (content, utilities)Regulated or high-value app (banking, health, enterprise)
Key storageKeystore, TEEKeystore with user authentication; StrongBox for signing keys where present
IntegrityPlay Integrity at sign-in, MEETS_DEVICE_INTEGRITY as a soft signalStandard requests on sensitive actions, MEETS_STRONG_INTEGRITY for high-value transactions, key attestation for device binding
TLSDefault config, cleartext offPinning with backup pins and forced update
BackupsExclude tokensExclude tokens and personal data, or require end-to-end encryption
ScreensNoneFLAG_SECURE on sensitive screens, review of appAccessRiskVerdict
VerificationOWASP MASVS L1 style baselineMASVS with the resilience group and annual independent MASTG testing

Small teams get most value from four things: target the current API level, keep exported components off, store tokens in Keystore-backed storage, and remove every embedded secret. Large organisations with many apps should centralise the attestation verifier and token service so each app team does not build its own.

Implementation roadmap

  1. Inventory and baseline: list apps, targetSdkVersion, SDKs and every secret found by scanning the built APK or AAB, not just source.
  2. Remove secrets first: move backend keys behind your API, rotate every key that has ever shipped, and restrict the client keys that remain.
  3. Fix the manifest: explicit exported values, signature permissions, debuggable false, backup rules and a release Network Security Configuration. Make Android Lint security checks blocking in CI.
  4. Migrate storage: move tokens to Keystore-backed encryption and plan the security-crypto exit in one release with a fallback read path.
  5. Integrity in observe mode: call Play Integrity, log verdicts server-side for several weeks without blocking, and measure how many genuine users fail each tier.
  6. Enforce in rings: start with high-value actions and a small percentage of traffic, using graded outcomes. Roll back by switching the server policy to observe, which needs no app release.
  7. Gate releases: MASTG-based tests and a secrets scan on every release build, with a minimum supported version so old, weaker builds can be retired.

Detection and measurement

  • Log server-side: integrity verdict distribution per app version, attestation failures, token exchange failures, and calls arriving without a valid device-bound token.
  • Watch embedded keys: usage of any client key by origin, and alerts for use outside expected package and certificate restrictions.
MetricTarget
Hard-coded secrets found in release buildsZero; any finding blocks release
Share of sensitive API calls backed by a verified integrity verdictAbove 95% for high-value apps
Exported components without a documented reasonZero
Active sessions on versions below the minimum supported versionFalling each quarter, under 5%
Time to rotate a leaked client key end to endUnder 24 hours

Framework mapping

AreaOWASP MASVS groupNIST SP 800-53 Rev. 5NIST CSF 2.0MITRE ATT&CK
Keystore and data storageMASVS-STORAGE, MASVS-CRYPTOSC-12, SC-28PR.DS-01T1409 Stored Application Data (Mobile)
Network Security ConfigurationMASVS-NETWORKSC-8PR.DS-02T1638 Adversary-in-the-Middle (Mobile)
Exported components and WebViewsMASVS-PLATFORMAC-6PR.PS-06n/a
Embedded secrets and token exchangeMASVS-AUTH, MASVS-STORAGEIA-5PR.AA-01T1552.001 Credentials In Files (Enterprise)
Play Integrity and attestationMASVS-RESILIENCESI-7PR.PS-06n/a
Release testingMASVS-CODESA-11ID.RA-01n/a

The mapping is NHI Mgmt Group's own. For the risk view, see the OWASP Mobile Top 10 Guide.

Common failure patterns

  • Cloud and AI keys in the APK: keys in BuildConfig, resources or SDK config files are extracted with standard decompilers. Moving them to native code or obfuscating them only slows extraction.
  • Debug settings in release: android:debuggable="true", a src="user" trust anchor in base-config, or cleartext enabled to make a test server work.
  • Pins without a backup: a certificate rotation breaks every installed copy, and the emergency fix is usually to remove pinning entirely.
  • Integrity checked on the device: the app reads its own verdict and decides, or the server never checks requestHash, so a hooked app replays a good verdict.
  • Exported by accident: an intent filter added for a feature makes a service or activity reachable by every app, and the handler trusts its extras.
  • Secrets in backups and logs: tokens in SharedPreferences included in cloud backup or device transfer, and tokens printed in Logcat during debugging that stay in release.

Lessons from incidents

The Symantec hard-coded AWS keys research showed that 77% of affected apps held valid AWS tokens and 47% held tokens with full access to private files in Amazon S3. The lesson for Android teams is that secrets often arrive through third-party SDKs, so scanning has to cover the compiled package and the SDK inventory, and key rotation has to be possible without breaking installed versions.

Practitioner checklist

  • Target the current API level and make Android Lint security warnings blocking in CI.
  • Scan every release APK or AAB for secrets and rotate any key that has ever shipped.
  • Store keys in Android Keystore, confirm a hardware security level, and plan the security-crypto migration.
  • Set android:exported explicitly on every component and use signature permissions for shared IPC.
  • Ship a Network Security Configuration with cleartext off, debug CAs only in debug-overrides, and backup pins.
  • Verify Play Integrity verdicts on the server, bound to the request, with graded outcomes.
  • Exchange attestation for short-lived, device-bound tokens; restrict any client key by package and certificate.
  • Define dataExtractionRules and fullBackupContent that exclude tokens and personal data.
  • Adopt Credential Manager for passkeys and retire legacy sign-in APIs.
  • Check Google's developer verification timeline for every distribution channel you use.

Standards and references

Related NHI Mgmt Group resources: Mobile App Security Guide · iOS App Security Guide · Mobile App Security Testing Guide · Android Enterprise Security Guide · Mobile Malware Guide

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Written and reviewed by Lalit Choda, NHI Mgmt Group. Last updated 24 October 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.