Leaked Third-Party API Key in a Consumer App
An Android consumer app calls a third-party geocoding provider. The API key is stored in BuildConfig, compiled into the APK, and sent as a query parameter on every request. A researcher decompiled the APK, extracted the key, and published it. The provider bill rose from about $200 to $4,300 in five days. Separately, a logging interceptor is active in release builds and writes full HTTP headers, including the bearer token, to logcat. The bearer token is stored in plain SharedPreferences. The app has no certificate pinning. On the account screen, screenshots are allowed, and a recent support screenshot exposed a user's email and partial card details. The team's proposed fix is to obfuscate the key with ProGuard and move it into native code.
1. Triage the issues in order. Explain why obfuscation and native code do not solve the API-key problem.
Read the worked answer
Immediate order: rotate the geocoding key to stop the financial bleed, then remove release logging of headers and tokens, then fix token storage, then address screenshots, then redesign the provider integration.
Obfuscation and native code raise the effort slightly but do not change the threat model. The key must be present in the app to be used, so it can be extracted from memory or from the native library. A determined attacker with the APK has everything needed to recover a client-side secret. Treat any key shipped in a mobile binary as public.
The architectural fix is to stop shipping the provider key to clients. Route geocoding through a backend-for-frontend that authenticates the user, applies per-user and per-IP rate limits, caches repeated queries, and holds the provider key server-side. If the provider supports application restrictions such as package name and signing certificate hash, apply them as defence in depth, but recognise that these can be spoofed and do not replace a proxy.
The logging issue is equally urgent because it leaks user bearer tokens. Release builds must not log authorization headers or response bodies containing personal data. Token storage should move to Android Keystore-backed storage, not plain SharedPreferences. The account screen should set FLAG_SECURE to block screenshots. These are separate controls; fixing the key does not fix token exposure.
2. Design the remediation architecture for the geocoding dependency, including how to handle abuse detection and cost control.
Read the worked answer
Introduce a backend endpoint such as POST /geo/lookup. The mobile app authenticates with its user session, not with the provider key. The backend validates the request, checks quota, calls the provider with the server-held key, normalises the response, and caches results by rounded coordinates and query text. Return only the fields the client needs.
Abuse controls: per-user rate limit, per-tenant or per-device anomaly detection, a global daily budget cap, and an alert when spend exceeds a rolling baseline. Log request counts and cache hit rate, not raw addresses. If the provider offers signed requests or short-lived tokens, use them server-side; do not issue long-lived provider credentials to the client.
Migration: ship a client release that calls the new endpoint, keep the old path available briefly with the old key disabled, and monitor 4xx and 5xx rates during the transition. Because app updates are not immediate, the server must tolerate old clients for a defined window, but the old key should be revoked immediately; old clients will fail and must be forced to update through a minimum-version check.
Cost control is not only rate limiting: cache aggressively, batch where the provider allows it, and set a hard budget alarm. The proxy also gives you a place to swap providers without another app release, which is a strategic benefit beyond the immediate incident.
3. The team wants to add certificate pinning as the main security fix. How should you respond, and what else should be verified before release?
Read the worked answer
Certificate pinning protects against a specific attack: a malicious or compromised certificate authority intercepting TLS. It does not protect a secret embedded in the app, does not stop logcat leakage, and does not secure tokens at rest. Making it the main fix would misdirect effort.
Pinning is still useful as defence in depth for the API domain, but it must be implemented with a backup pin and a rotation plan. A pinned app that cannot connect after a certificate change becomes an availability incident. Prefer pinning to the backend you control, not to a third-party geocoding domain that the client should no longer call directly.
Before release, verify: release builds have logging disabled or redacted; bearer tokens are stored in Keystore-backed storage; the account screen has FLAG_SECURE; the provider key is revoked and absent from the new binary; the backend enforces authentication and quotas; and crash reporting does not capture personal data. Add a static check in CI that fails if a known secret pattern appears in BuildConfig or resources. Also confirm that the minimum supported app version blocks clients still using the compromised key. The response should be: rotate, remove the secret from the client, fix token handling, then add pinning with a rotation plan.