Hardcoded Signing Key in Android App Bypasses Paywall for Every Article
The Risk
A secret key hidden inside the news publication's Android app could be recovered offline by anyone with a copy of the app, and used to make the server believe any browser was a paying subscriber. The bypass takes about five seconds: paste a small block into any browser, reload, paywall gone, every article reads as if the visitor were a full subscriber. The script could be posted once on a social site and every reader becomes a free subscriber. Rotating the key alone does not fix it, because the next version of the app would leak the next key the same way.
The Vulnerability
The publication's Android app generated a session token, signed it with a shared secret, and sent it to the website as a cookie that the server treated as proof of an in-app paying subscriber. Two things went wrong.
First, the signing secret was derivable entirely from constants inside the public app binary. It lived as an encrypted blob inside the app's resources. The decryption key was derived from a hardcoded literal string used as both password and salt. Recovery is offline, deterministic, and takes a single command.
Second, the metering endpoint that decides whether to show the paywall did not validate the signature on the token at all. Tokens with no signature and tokens signed with arbitrary wrong keys were both accepted. The server also did not verify the subscription identifier inside the token against an authoritative receipt store.
The Attack
Recover the signing key
Reversing the public Android app revealed the static encrypted blob and the hardcoded password and salt. A short script reproduced the key derivation and printed the signing secret in plaintext. Every shipped copy of the app embeds the same key.
Forge the subscriber token
A small browser snippet constructed a session token with subscriber claims, signed it with the recovered secret using the same algorithm the app uses, and set the resulting cookie on the publication's domain alongside the matching device-id cookie the server cross-checks against the token.
Bypass the paywall
On reload, the paywall overlay disappeared and the full article body rendered. The server's own metering response confirmed the elevation: granted true, grant reason "SUBSCRIBER", is-subscriber true. The header even replaced the "Subscribe" button with "Sign in". Any further paywalled article in the same browser loaded immediately with no overlay. Cookies persist, so the bypass is not article-specific and not session-bound.
The Impact
- Free permanent access to every paywalled article on the publication for any visitor who runs a small browser snippet. No account, no payment, no rate limit.
- Scales infinitely. The snippet can be posted as a social-media post or code gist, and every reader becomes a free subscriber.
- Subscription revenue impact on a per-visitor basis. A multi-dollar monthly subscription is bypassed in five seconds.
- Server response confirms full subscriber elevation, not just article unlock, suggesting downstream features that gate on subscriber state are also affected.
- Static signing keys in distributed binaries cannot be made safe by rotation alone. The next app release would leak the next key by the same mechanism.
Remediation
- Validate the signature on the session token server-side. Reject unsigned tokens and tokens signed with wrong keys.
- Verify the subscription identifier inside the token against the authoritative receipt store (Google Play or Apple) on every request, not just at issuance.
- Stop deriving the signing secret from constants inside the distributed binary. Use server-issued, short-lived tokens minted only after a real receipt check.
- Rotate the current key as part of the fix, but do not treat rotation alone as a remediation. Plan the change so older app versions continue to work via a server-side receipt re-validation path.
- Forensic review of access patterns on the metering endpoint to estimate the affected free-read population and assess revenue impact.
Why Mobile Matters Here
The signing secret was unreachable from web testing alone. Recovery required pulling the Android app, decoding its resources, and following the key-derivation chain through decompiled code. The vulnerability presents as a server-side trust failure, but the attack surface only opens once the secret has been extracted from the mobile binary.