Mobile
Root and jailbreak detection: why it matters and how to implement it
On a rooted or jailbroken device an app's protections weaken. Why security reviews rate this as high risk and how to implement detection properly.
· 6 min read

When the mobile app of our own product went through its security review, the first high-severity finding in the report read: "Root detection not implemented" (MASWE-0097, OWASP Mobile Top 10 2024 M7). The iOS app had the same finding — no jailbreak detection. Many developers treat this as a secondary concern. The review, however, rates it as high risk. Let's look at why, and how to close it.
What root and jailbreak are
Android and iOS run every app inside its own sandbox. One app cannot read another app's files or change system files. A large part of mobile security rests on this isolation.
Root (Android) and jailbreak (iOS) remove these restrictions. The user, or anyone else who gets hold of the device, gains the highest privileges and can open any app's folder, intercept system calls and read memory.
Why it is a problem for the app
A rooted device is not a crime in itself; often it is simply a curious user. The problem is that on such a device the app's other protection layers weaken too:
- Stored data becomes exposed. Files in internal storage, the database and preferences become readable to other processes.
- Dynamic analysis becomes easier. Tools like Frida work most easily on a rooted device.
- Certificate validation can be bypassed. It becomes possible to install a third-party CA at system level or to disable the validation function with a hook.
- Malware becomes more powerful. If a malicious app on the device has root access, it can reach your app's data as well.
For an app that handles financial, tax or medical data, this environment is unacceptably risky. That is why the RESILIENCE group of MASVS expects the app to check its environment.
Root detection does not protect data by itself. It tells the app: "in this environment, your other protections cannot be trusted."
How detection works
There is no single reliable check, so several signals are checked together.
Android
- An
subinary in common locations:/system/bin/su,/system/xbin/su,/sbin/su. - Packages or files of root managers such as Magisk and SuperSU.
- A system build signed with
test-keys(ro.build.tags). - A writable
/systempartition. - Dangerous system properties, for example
ro.debuggable=1. - Server-verified device attestation — the Google Play Integrity API. This is the strongest signal, because the verdict is signed on Google's servers, not inside the app, and checked by your backend.
iOS
- Jailbreak apps and files: Cydia, Sileo,
/Applications/Cydia.app,/private/var/lib/apt. - Attempting to write outside the sandbox: a normal app should not be able to write a file under
/private. - Foreign dynamic libraries loaded into the app process (for example MobileSubstrate).
- The ability to open URL schemes such as
cydia://.
How we implemented it
You can write these checks yourself, but root-hiding tools (such as Magisk's hiding modules) are updated constantly, and hand-written checks age quickly. So in our Flutter app we used a RASP library, freeRASP. It checks root, jailbreak, emulators, hooks, debuggers and app integrity in one place and raises a separate signal for each.
What we paid attention to during implementation:
- The check starts when the app launches, before the login screen. No sensitive data should be loaded yet.
- When a threat is detected, a blocking screen is shown. It explains in plain language what happened: the app cannot run in an insecure environment. No alarming wording.
- The check is not one-off. RASP keeps watching at runtime, because root access can be gained after the app has opened.
- Release and debug builds are separated. During development you need emulators and debuggers, so blocking is enabled only in the release build. Make sure that setting cannot slip into a release in its disabled state.
Block or warn?
This is a business decision. There are two approaches:
- Block — the app does not run on a rooted device at all. The usual choice for financial and government apps, and reviews accept it well.
- Restrict — the app opens, but critical actions such as payments or viewing sensitive data are disabled, and the server is notified.
Merely showing a warning and allowing everything is not enough from a review's point of view.
One more important point: do not keep the detection result only inside the app. Where possible, share it with the server too (for example via a Play Integrity token). An in-app check can be switched off with a hook; a server-side check is much harder to bypass that way.
Test it
After implementation, test the result in practice:
- Run the release build on a rooted Android device (or an emulator with Magisk).
- Repeat with a root-hiding module enabled.
- Test on a jailbroken iOS test device.
- Make sure there are no false positives on a normal device — that is the worst outcome for real users.
Conclusion
Root and jailbreak detection is not the app's only protection, but it is a precondition for all the other protections to work reliably. Together with RASP, certificate pinning and secure storage, it meets the review's expectations.
If you want to know how well root and jailbreak detection works in your app, request a security scan. We will check your APK or IPA and help you prepare for the review.


