NO NETWORK · NO TELEMETRY · FAILS CLOSED · v0.3.0

v0.3.0 · MIT · New Architecture

Device integrity for React Native,that fails closed.

Jailbreak, root, hooking, debugger, emulator and opt-in tamper signals for React Native and Expo. No network. No telemetry. Unknown is never clean.

IntegrityGate.tsx
// npx expo install react-native-device-integrity
import { useDeviceIntegrity } from "react-native-device-integrity";

function IntegrityGate({ children }: { children: React.ReactNode }) {
  const { status, result, loading } = useDeviceIntegrity();

  if (loading && result == null) {
    return null; // do not flash protected UI
  }

  if (status === "clean") return <>{children}</>;
  return <BlockedScreen status={status} />;
}

What it detects

Six areas.Typed signal ids.

Descriptions are generic on purpose — no matched paths or package names. Tamper checks run only when you pass the corresponding options.

Jailbreak

iOS: jailbreak_files, jailbreak_url_schemes, jailbreak_symlinks, jailbreak_writable_system.

Root & bootloader

Android: root_su_binary, root_management_apps, root_magisk_files, root_test_keys, root_dangerous_props, root_rw_system — plus bootloader_unlocked for an unlocked bootloader.

Hooking

iOS: hooking_libraries, hooking_dyld_insert. Android: hooking_frida, hooking_xposed.

Debugger

Both platforms: debugger_attached — fires whenever a debugger is attached.

Emulator

iOS: simulator. Android: emulator. Reported separately; compromising only with treatEmulatorAsCompromised or policy.

Tamper

Opt-in. iOS: tamper_binary_decrypted, tamper_team_id_mismatch. Android: tamper_signature_mismatch, tamper_untrusted_installer.

Reference

Every check, explained.Mechanism, exploit, bypass, references.

One page per signal: what the native code inspects, the exploit it surfaces, how it can be bypassed, and where to read more — OWASP MASTG, Apple and Android docs.

Result semantics

Three statuses.Unknown is never clean.

Status is resolved from the native report plus options. Treat only clean as safe. Block or degrade on both compromised and unknown.

01

clean

The run completed and no non-ignored compromising signal was present.

02

compromised

Any non-ignored signal whose category is in the compromising set — even if the run was incomplete.

03

unknown

Incomplete, timed-out, missing-module, or unsupported-platform. Unknown is never clean.

Resolution rules

Compromise evidence wins.Everything else follows.

Apply ignore first. Build the compromising category set. Then resolve in this order.

  1. 01

    Compromise evidence wins

    Any non-ignored signal in the compromising category set → compromised, even if the run was incomplete.

  2. 02

    Emulator and report-only stay separate

    Emulator/simulator signals stay in signals but do not change status unless treatEmulatorAsCompromised or policy includes emulator. The same goes for a signal the app set to report at build time (bootloader_unlocked: "report").

  3. 03

    Incomplete → unknown

    If the run did not complete and there is no compromising evidence → unknown.

  4. 04

    Else clean

    Otherwise → clean. Treat only clean as safe; block or degrade on compromised and unknown.

Configure

Two build-time options.Everything else per call.

The Expo config plugin writes these at prebuild. In a bare app, add the same entries by hand — the native code reads them from the manifest and Info.plist.

app.json (Expo)
{
  "expo": {
    "plugins": [
      [
        "react-native-device-integrity",
        {
          "android": { "bootloaderUnlocked": "report" },
          "ios": { "jailbreakUrlSchemes": true }
        }
      ]
    ]
  }
}
Bare React Native
<!-- android/app/src/main/AndroidManifest.xml, inside <application> -->
<meta-data
  android:name="com.deviceintegrity.bootloader_unlocked"
  android:value="report" />

<!-- ios/<App>/Info.plist: LSApplicationQueriesSchemes -->
<!-- cydia, sileo, zbra, filza, undecimus, activator -->

android.bootloaderUnlocked

Build time. "compromised" (default): an unlocked bootloader makes status compromised, like Play Integrity's device verdict. "report": bootloader_unlocked is still returned but never compromising on its own. "off": the check doesn't run. Unknown values count as compromised. Relaxing it never hides root — the root signals are separate checks — but it weakens the backstop when root is hidden.

ios.jailbreakUrlSchemes

Build time, Expo only. Default true: the plugin adds the jailbreak URL schemes to LSApplicationQueriesSchemes, without which the URL-scheme check finds nothing. Set false if you manage Info.plist yourself; bare apps add the schemes by hand.

Runtime options

Per call to checkIntegrity / useDeviceIntegrity: ignore (signal ids moved to ignored), treatEmulatorAsCompromised, policy.compromisingCategories, timeoutMs, and the opt-in tamper checks under android / ios. E.g. ignore: __DEV__ ? ["bootloader_unlocked"] : [] for development builds only.

Testing guides

Prepare a device you own.Then test the checks.

Android compares Magisk, KernelSU, and APatch after a bootloader unlock. iOS starts from chip and iOS coverage, then palera1n on checkm8 or Dopamine on A12 and later. No jailbreak? Embed Frida Gadget in your app and test hooking detection on any stock iPhone.

How it compares

A snapshot of popular options,as of September 2026.

Check each project for current details. None replace server-side attestation for high-value actions.

This library

device-integrity

Device integrity signals

MIT

jail-monkey

Jailbreak/root + device flags

RASP

freeRASP

Full RASP / app shielding

Expo

expo-device

Device info

Info

device-info

Device info

Coverage

Focus
Device integrity signals
Jailbreak/root + device flags
Full RASP / app shielding
Device info
Device info
Jailbreak / root
✅
✅
✅
Experimental (isRootedExperimentalAsync)
—
Hooking frameworks
✅ iOS + Android
Android: suspicious apps
✅
—
—
Debugger attached
✅
Debug-build check
✅
—
—
Emulator / simulator
✅ (reported separately)
—
✅
isDevice
isEmulator()
App tampering…
Signature, installer (Android); encryption, Team ID (iOS) — opt-in
—
✅
—
—

Model & ops

Result model
clean / compromised / unknown + signal ids + reason
Booleans
Per-threat callbacks
Boolean / throws
Boolean
Failed checks
Reported as unknown, never clean
Not documented
Not documented
Throws
Not documented
Network / telemetry
None
None
Security telemetry to Talsec (part of the free plan)
None
None
Licence / cost
MIT, fully open source
MIT
MIT wrapper + proprietary SDK; free up to 100k devices
MIT
MIT
Architecture
New Architecture (TurboModule)
New + old architecture
Not documented
Expo module
Not documented
Expo config plugin
✅
—
✅
Built in (Expo)
—
  • Snapshot as of September 2026. Check each project for current details.

  • Pick this library if you want a small, fully open-source, zero-network check with typed, fail-closed results that you can audit end to end.

  • Pick freeRASP if you need broad RASP coverage (tampering, store, screen capture, malware) and managed reporting, and can accept telemetry and its fair-usage terms.

  • Pick jail-monkey if you also need its extra device flags (mock location, ADB, developer settings) or old-architecture support.

  • None of these replace server-side attestation (App Attest / Play Integrity) for high-value actions.

Limitations & threat model

Client-side risk indicators.Not a RASP replacement.

Client-side indicators

They can be bypassed by an attacker who controls the device — Frida / objection hooking this module, rootless jailbreaks with hiding tweaks, Magisk DenyList / Zygisk / Shamiko, KernelSU hiding.

Not attestation

Never rely on them alone for security decisions. For high-assurance flows, use Apple App Attest / DeviceCheck and the Google Play Integrity API server-side.

False positives

Custom ROMs, developer devices with test-keys builds, developer phones with an unlocked bootloader (bootloader_unlocked, configurable per app), and enterprise MDM environments can trip signals.

Check categories informed by OWASP MASVS/MASTG, IOSSecuritySuite (BSD-2-Clause ≤1.9.11; no source copied), and RootBeer (Apache-2.0; independent implementation).

Install the library.Audit the signals.

npx expo install react-native-device-integrity · New Architecture required · Expo Go not supported