// FINDING / MOBILE

Hardcoded API keys

CriticalMobile

API keys, cloud credentials, signing secrets or encryption keys are compiled into the mobile app or shipped in its resources. Anyone can download the app, unpack it and read them with free tools; obfuscation only slows this down.

At a glance

Why it matters
Every installation carries the secret, so it cannot be revoked per user. Depending on the key, attackers call paid APIs at your expense, read data from cloud storage, send push notifications to all users or impersonate the back end. Keys also live on in old app versions and public repositories.
How to fix it
Keep secrets on the server and have the app call your back end, which brokers requests to third parties with its own credentials. Where a client key is unavoidable, restrict it by app signature, bundle id and API scope. Rotate any key that has shipped and scan builds for secrets in CI.

Description

Hardcoded API keys, tokens or cloud credentials are secrets embedded directly in an application's source code, compiled binary, resource files or configuration bundled with the app, rather than retrieved at runtime from a secure store. In a mobile app this is especially exposed: the app package is distributed to every installation, so the secret sits on every user's device, extractable through decompilation, resource extraction or simple string searching, no server-side access required at all.

Impact

Once extracted, a hardcoded key grants whatever the key itself allows: backend API access, cloud storage access, third-party service usage billed to your account, or in some cases direct database or infrastructure access if the key was never scoped down. Because the key is embedded once and distributed to everyone, revoking it after discovery is the only remedy, and every existing installation loses access to whatever depended on it until updated, which is a disruptive fix compared to never embedding the secret at all.

How we find it

  • We decompile and disassemble the application binary and search extracted resources, strings and configuration files for patterns matching known API key formats and generic high-entropy strings.
  • We intercept the app's own network traffic (through a proxy) to see which keys and tokens it actually sends, since some secrets only appear in memory or in a request, not in any static file.
  • We check public repositories and build artefacts associated with the app for the same secrets, since a key removed from the shipped app but still present in git history or a public CI log is just as compromised.

Fix

Never embed a long-lived secret in application code or resources that ship to end-user devices. Fetch short-lived, scoped tokens from your own backend at runtime instead, have the backend hold the long-lived credential, and rotate any key that has ever been embedded in a shipped build, since it must be treated as already exposed.

// Vulnerable: a long-lived, unscoped key embedded directly in the app
val apiKey = "sk_live_51Hxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
val response = api.call(endpoint, apiKey)

// Fixed: the app authenticates to your own backend, which holds the
// long-lived credential and issues short-lived, scoped tokens instead
val sessionToken = backend.authenticate(userCredentials)  // short-lived
val response = api.call(endpoint, sessionToken)

References

  • OWASP Mobile Top 10: M1, Improper Credential Usage
  • CWE-798: Use of Hard-coded Credentials
  • OWASP Mobile Application Security Testing Guide (MASTG)