Your mobile app is a credential vault: what we find when we unzip the binary
A mobile app isn't a locked door. It's a file you hand to the attacker. Once it's on a device, everything compiled into it — every key, every endpoint, every "hidden" check — is theirs to read at leisure. On a recent assessment of an enterprise CRM client, reverse-engineering the shipped binary turned up a working credential to a live customer-data API before we'd even launched the app. This is a tour of what we routinely find in that binary, drawn from real engagements, and how to make the file worth a lot less to whoever unzips it.
1. Secrets compiled into the build
The first thing we do is treat the app as an archive, not a program. Unpack it, and read the strings. Developers still ship API keys, backend credentials, signing secrets and third-party tokens inside the bundle, on the assumption that "nobody will look." People look.
On the CRM engagement, the binary contained hardcoded backend credentials. We confirmed — carefully, read-only — that they granted a live, authenticated session to an internal customer-data API. No exploit, no clever trick: the keys to a production API were in a file on every customer's phone.
The fix is architectural, not cosmetic. Obfuscation buys you minutes. The real answer is that the app should never hold a long-lived secret at all: authenticate the user via SSO/OAuth, broker access to backend APIs server-side, and scope every token to that user and session. If a value in the bundle would be dangerous in an attacker's hands, it doesn't belong in the bundle.
2. "Encrypted" local storage with a recoverable key
Most apps that hold data offline encrypt it. The question is never "is it encrypted" — it's "where does the key come from?" If the key is derived from something on the device, the encryption is a speed bump.
On the same app, the offline store was encrypted, but the key was derived from unsalted hashes and non-cryptographic randomness — all of it recoverable from the device. We reconstructed the key and decrypted the local database. Encryption that an attacker on the device can undo is not protecting the data; it's protecting the compliance checkbox.
Derive keys properly with a modern KDF (PBKDF2, scrypt or Argon2) and a real CSPRNG, and — crucially — store the resulting key in the platform's hardware-backed keystore (iOS Keychain/Secure Enclave, Android Keystore), not alongside the data it protects.
3. Root/jailbreak detection that's one boolean deep
Many apps try to refuse to run on a rooted or jailbroken device. Almost all of them implement it as a single function that returns true or false — which means a single runtime hook flips it. On the CRM app, one Frida hook disabled the check entirely.
This isn't a reason to skip the control; it's a reason to be honest about what it buys you. Root detection is a nuisance for casual attackers, not a security boundary. Treat it as telemetry and defence-in-depth, assume it will be bypassed, and never let it be the only thing standing between an attacker and sensitive data.
4. Certificate pinning that a config silently disables
Pinning stops an attacker intercepting the app's traffic even with a trusted certificate. It's one of the most valuable mobile controls — when it's actually on. On this engagement, an MDM configuration default silently disabled TLS certificate pinning, re-opening the app to full session interception for any managed device in that state.
A control that a configuration flag can quietly switch off is a control you can't rely on. Pin by default, fail closed, and alert when pinning is disabled rather than degrading silently.
5. The hybrid-app bridge that leaks its own token
Hybrid apps often run a local web server or runtime bridge on the device so the native and web layers can talk. That bridge is usually protected by a token — and on this app, the token meant to stop other apps driving the bridge was disclosed in a single unauthenticated request to any co-located app. The lock shipped with its own key taped to it.
Bind bridge tokens to the app's own context, never expose them to other local processes, keep them out of URLs, and serve the bridge over authenticated localhost TLS.
What to take from this
- The binary is public. Design as if the attacker has already read every line of it — because they have.
- No long-lived secrets in the bundle. Broker access server-side; scope tokens to the user and session.
- Key management beats encryption. Where the key lives decides whether "encrypted" means anything.
- Client-side checks are telemetry, not boundaries. Root detection and pinning help, but the server must assume a hostile client.
When did you last unzip your own app?
A mobile penetration test does exactly this — static and dynamic, across iOS, Android and hybrid builds — and shows you what the shipped binary gives away. It's core work for our penetration testing team.
Scope a mobile test