HS256 License Secret Shipped in the APK
An Android productivity app uses a JWT as an offline license. The token is HS256, contains plan (free or premium), sub, and exp, and is valid for 365 days. The same HMAC secret is present in strings.xml and is used by the client to verify cached licenses and by the server at /v1/license/validate to decide which features to unlock. The app has 12,000 installs, supports offline use for 30 days, and pins the API certificate. A tester decompiles the APK, extracts the secret, and forges a token with plan=premium and a future exp; the server accepts it and returns premium feature flags. The server rejects alg=none. The team argues that certificate pinning protects the secret in transit and that the token is not a password.
1. Why do pinning and TLS not mitigate this finding? Identify the trust boundary that is broken.
Read the worked answer
TLS and pinning protect the channel between the app and server. They do not protect a secret that is shipped inside the app: anyone who downloads the APK can read strings.xml, and pinning does not prevent decompilation or dynamic extraction. The broken trust boundary is the license decision: the server uses a symmetric secret that every client possesses to decide whether a token is authentic. Therefore every client is a potential issuer. The server cannot distinguish a token minted by the developer from one minted by a user because both use the same HMAC key. Rejecting alg=none is irrelevant when the real key is available to attackers.
2. Propose a replacement licensing design that supports offline use and resists token forgery.
Read the worked answer
Use asymmetric signatures. The server holds an Ed25519 or ECDSA private key and signs license tokens; the app embeds only the public key and verifies. The token should include sub, plan, exp, iat, a key ID, and a device or account binding. For offline use, issue a short-lived signed license, for example 7 to 30 days, and refresh online; include a grace period. Server-side premium actions must check entitlement independently, not trust a client flag. Add Play Integrity or App Attest for high-value actions, and keep the signing key in an HSM or KMS. If using JWT, use alg=EdDSA or ES256 and reject all other algorithms explicitly.
3. What quick mitigations can reduce impact before the redesign, and what residual risk remains?
Read the worked answer
Short term: rotate the HMAC secret, invalidate all existing licenses, shorten the 365-day lifetime, bind tokens to account and device, and add server-side anomaly detection. But the client still must verify something; if the same symmetric secret remains in the app, forgery remains possible. Move verification to a public key and stop issuing client-verifiable HMAC licenses. Residual risk: old APKs with the leaked secret will continue to work until the server rejects that key ID; plan a forced update and a server-side key-version cutoff.