Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 115 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,42 @@
# jailbreak_root_detection

[![pub package](https://img.shields.io/pub/v/jailbreak_root_detection.svg)](https://pub.dartlang.org/packages/jailbreak_root_detection)
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

Uses [RootBeer](https://github.com/scottyab/rootbeer) + DetectFrida for Android root detection and [IOSSecuritySuite (~> 1.9.10)](https://github.com/securing/IOSSecuritySuite/tree/1.9.10) for iOS jailbreak detection.
Detects rooted, jailbroken, tampered and otherwise untrusted devices from Flutter.

## Getting started
Uses [RootBeer](https://github.com/scottyab/rootbeer) + Magisk and Frida checks for Android root detection, and [IOSSecuritySuite (~> 1.9.10)](https://github.com/securing/IOSSecuritySuite/tree/1.9.10) for iOS jailbreak detection.

In your flutter project add the dependency:
## Requirements

```yaml
jailbreak_root_detection: "^1.2.1"
```
| | Minimum |
| --- | --- |
| Flutter | 3.44.0 |
| Dart SDK | 3.12.0 |
| Android | minSdk 21, compileSdk 34, Java/Kotlin 17 |
| iOS | 11.0 |

## Usage
The iOS side ships as a Swift Package (Swift Package Manager). A CocoaPods podspec is still
included, so both dependency managers work.

### Important: Test on Real Devices Only
## Getting started

This package must be tested on a real device (physical device).
Add the dependency to your `pubspec.yaml`:

Running on an emulator or simulator may cause false positives — for example, the detection may incorrectly report that the device is jailbroken or rooted.
```yaml
dependencies:
jailbreak_root_detection: "^1.2.3"
```

### Android
Or:

```dart
final isNotTrust = await JailbreakRootDetection.instance.isNotTrust;
final isJailBroken = await JailbreakRootDetection.instance.isJailBroken;
final isRealDevice = await JailbreakRootDetection.instance.isRealDevice;
final isOnExternalStorage = await JailbreakRootDetection.instance.isOnExternalStorage;
final checkForIssues = await JailbreakRootDetection.instance.checkForIssues;
final isDevMode = await JailbreakRootDetection.instance.isDevMode;
```shell
flutter pub add jailbreak_root_detection
```

### iOS
### iOS setup

- Update `Info.plist`
To let the plugin probe for jailbreak-related URL schemes, add them to `ios/Runner/Info.plist`:

```xml
<key>LSApplicationQueriesSchemes</key>
Expand All @@ -47,16 +50,100 @@ final isDevMode = await JailbreakRootDetection.instance.isDevMode;
</array>
```

Without this entry iOS blocks the `canOpenURL` checks and jailbreak detection is less accurate.

### Android setup

No extra configuration required.

## Usage

```dart
import 'package:jailbreak_root_detection/jailbreak_root_detection.dart';

final detector = JailbreakRootDetection.instance;

// One combined verdict — the usual entry point.
final isNotTrust = await detector.isNotTrust;
if (isNotTrust) {
// Block, warn, or degrade functionality.
}
```

### API

| Member | Returns | Android | iOS | Description |
| --- | --- | :---: | :---: | --- |
| `isNotTrust` | `Future<bool>` | ✅ | ✅ | Combined verdict: jailbroken/rooted, not a real device, or (Android) installed on external storage. Returns `true` if any check throws. |
| `isJailBroken` | `Future<bool>` | ✅ | ✅ | Rooted (RootBeer, Frida, Magisk) on Android; jailbroken on iOS. |
| `isRealDevice` | `Future<bool>` | ✅ | ✅ | `false` on an emulator or simulator. |
| `isDebugged` | `Future<bool>` | ✅ | ✅ | A debugger is attached to the process. |
| `isDevMode` | `Future<bool>` | ✅ | — | Developer options are enabled. |
| `isOnExternalStorage` | `Future<bool>` | ✅ | — | The app is installed on external storage. |
| `isTampered(String bundleId)` | `Future<bool>` | — | ✅ | The app bundle/signature has been modified. |
| `checkForIssues` | `Future<List<JailbreakIssue>>` | ✅ | ✅ | All detected issues in one call. |

Android-only members throw a `MissingPluginException` on iOS and vice versa, so guard them with
`Platform.isAndroid` / `Platform.isIOS`:

```dart
final isNotTrust = await JailbreakRootDetection.instance.isNotTrust;
final isJailBroken = await JailbreakRootDetection.instance.isJailBroken;
final isRealDevice = await JailbreakRootDetection.instance.isRealDevice;
final checkForIssues = await JailbreakRootDetection.instance.checkForIssues;
if (Platform.isAndroid) {
final isOnExternalStorage = await detector.isOnExternalStorage;
final isDevMode = await detector.isDevMode;
}

if (Platform.isIOS) {
const bundleId = 'com.w3conext.jailbreakRootDetectionExample';
final isTampered = await detector.isTampered(bundleId);
}
```

final bundleId = 'my-bundle-id'; // Ex: final bundleId = 'com.w3conext.jailbreakRootDetectionExample'
final isTampered = await JailbreakRootDetection.instance.isTampered(bundleId);
### checkForIssues

`checkForIssues` runs every check the platform supports and returns only the problems it found —
an empty list means the device looks clean.

```dart
final issues = await detector.checkForIssues;
for (final issue in issues) {
print('issue: $issue');
}
```

### Reference
| `JailbreakIssue` | Android | iOS | Meaning |
| --- | :---: | :---: | --- |
| `jailbreak` | ✅ | ✅ | Device is rooted or jailbroken. |
| `notRealDevice` | ✅ | ✅ | Running on an emulator or simulator. |
| `debugged` | ✅ | ✅ | A debugger is attached. |
| `fridaFound` | ✅ | ✅ | The Frida instrumentation framework was detected. |
| `devMode` | ✅ | — | Developer options are enabled. |
| `onExternalStorage` | ✅ | — | App is installed on external storage. |
| `proxied` | — | ✅ | An HTTP proxy is configured. |
| `reverseEngineered` | — | ✅ | Reverse-engineering tooling was detected. |
| `cydiaFound` | — | ✅ | Cydia was detected. |
| `tampered` | — | — | Reported only by `isTampered(bundleId)`, not by `checkForIssues`. |
| `unknown` | ✅ | ✅ | An issue this Dart version doesn't recognise. Android currently reports Magisk detection here. |

Handle `unknown` as untrusted rather than ignoring it.

## Important: test on real devices only

This package must be tested on a physical device.

Running on an emulator or simulator may cause false positives — for example, detection may
incorrectly report that the device is jailbroken or rooted.

## Example

See [`example/lib/main.dart`](example/lib/main.dart) for a complete app that runs every check
and prints the results.

## Reference

- [RootBeer](https://github.com/scottyab/rootbeer)
- [IOSSecuritySuite](https://github.com/securing/IOSSecuritySuite)
- [trust_fall](https://github.com/anish-adm/trust_fall)

## License

- https://github.com/anish-adm/trust_fall
[MIT](LICENSE)
Loading