Root detection, pinning, and what they actually buy you
Every mobile assessment reaches the same two questions: is the app checking for a rooted device, and is it pinning its certificates. Both controls are worth having. Neither is a security boundary, and treating them as one is how apps end up hardened on the outside and open underneath.
Key takeaways
- Root and jailbreak detection raises cost for an attacker. It does not stop one, because the check runs on hardware the attacker controls.
- Certificate pinning stops interception by a third party on the network. It does not stop the owner of the device, who can patch the app.
- Both are worth implementing anyway, for the same reason a lock is worth fitting to a glass door: most people are not carrying a glass cutter.
- The findings that matter are usually underneath: data left in local storage, a session that outlives logout, an exported component, or an API that trusts the client.
- If removing the app entirely and calling the API directly gets an attacker what they want, no amount of client hardening was ever going to help.
The premise every mobile control rests on
A mobile app runs on a device somebody else owns. They can inspect it, modify it, run it under a debugger, hook its functions at runtime, and rebuild it with any check removed. Nothing that executes on the client is a decision an attacker cannot revisit.
That is not an argument against client-side controls. It is an argument about what they are for: raising cost, filtering out casual attackers, and slowing down automated abuse. It is only a problem when a control is mistaken for a boundary and something important is placed behind it.
The question that settles most mobile findings
If the app were deleted and the API called directly, what would still be protected? Whatever survives that question is your real security. Everything else was a speed bump, and worth knowing as one.
Root and jailbreak detection
The app checks whether the device has been rooted or jailbroken and refuses to run, or degrades, if it has. Implementations look for known binaries, writable system paths, package managers, debugger presence, or emulator artefacts.
All of it runs on the attacker device, which is the whole problem. A hooking framework can intercept the function that performs the check and return the answer the app wants. Bypassing detection is routine work, and on a well-known implementation it takes minutes rather than hours.
What makes it worth having anyway
- It excludes the large population of attackers who will not install tooling.
- It makes automated abuse at scale more expensive, because every device in the farm needs preparing.
- It is often a compliance or partner requirement, and meeting it costs little.
- Detection spread across several checks in different places is meaningfully more annoying to remove than a single function returning a boolean.
What makes it worthless is a single well-named function called once at startup. That is one hook. If you are going to implement it, implement it more than once, check at points that matter rather than only at launch, and do not name the function after what it does.
Certificate pinning
The app refuses connections whose certificate is not the one it expects, rather than accepting anything the device trust store vouches for. It is a genuinely valuable control and it stops a real attack: interception by somebody who has managed to place a certificate in the trust store.
It does not stop the device owner. The same hooking that defeats root detection defeats pinning, and a tester who cannot see your traffic simply patches the app until they can. That is expected and it is not a finding.
The finding is when pinning is the only thing protecting something. If your API accepts a request that the app would never send, pinning bought you nothing, because it never protected the endpoint. It protected the pipe.
Pinning has an operational cost worth naming
A pinned certificate has to be rotated before it expires, in an app release, through a store review, onto devices that update whenever their owners feel like it. Pin to an intermediate or pin more than one key, and have a plan for the day rotation goes wrong, because an app that cannot connect is indistinguishable from an outage.
What the app leaves on the device
This is where mobile assessments find their more serious material, and it does not require defeating anything. Data written to the device is readable on a device the attacker controls, and often on one they have merely borrowed.
- Tokens or credentials in plain preference stores rather than the platform keystore or keychain.
- Personal data cached in a local database and never cleared when the user signs out.
- Sensitive values written to logs, which on a shared or managed device are readable by more parties than you think.
- Backups that include application data, restorable onto another device.
- Screenshots taken by the operating system when the app is backgrounded, capturing whatever was on screen.
The recurring one is data that survives logout. A user who signs out on a shared device has told you they are finished; if the local cache still holds their information, the sign-out was cosmetic. That belongs to a broader pattern covered in what logging out should actually do.
The platform surface people forget
A mobile app is not only a client for your API. It registers with the operating system, and what it exposes there is reachable by other applications on the same device.
- Components exported to other apps that were only ever meant to be reached internally.
- Deep links and custom URL schemes that accept parameters and act on them without checking who sent them.
- Inter-process interfaces that assume the caller is your own code.
- A minimum supported platform version low enough that the app will install on releases that stopped receiving security fixes years ago.
These are cheap to find and cheap to fix, and they are missed consistently because they do not appear anywhere in the user-facing product. Nobody tests a screen that does not exist.
What to ask for when you scope one
A mobile assessment that only looks at the app is half a test. Most of what matters is the API behind it, and most serious findings live there rather than in the binary.
- Scope the API alongside the app, not instead of it and not as a separate engagement.
- Provide at least two accounts, so authorisation between users can actually be tested.
- Expect the tester to bypass your pinning and root detection, and expect that not to be a finding in itself.
- Ask for both platforms if you ship both. The two codebases fail differently and the findings rarely match.
- Say which platform versions you support, because it decides which protections the tester can assume are present.
Our guide to scoping a penetration test covers the rest of what a tester needs before quoting.