iOS - Jailbreak - Detector (Pro)
Jailbreaking lifts the iOS sandbox and gives an attacker free rein to inject code (MobileSubstrate, libhooker, Substitute), patch your binary, read/write the filesystem, and run reverse-engineering tools like Frida, Cycript, or SSL Kill Switch. Use the 'IOSJailbreakDetector' to detect a jailbroken host and react accordingly. This detector rounds out platform parity with the Android device detectors.
Detector
The 'IOSJailbreakDetector' does not require any monitor. On demand, it delegates to a native Objective-C++ plugin ('com.gups.anticheat', exported symbol 'GupsAntiCheat_ScanJailbreak') that runs up to six independent probes in a single batched scan:
URL scheme probe: Asks 'UIApplication.canOpenURL' for known jailbreak URL schemes (cydia, sileo, zbra, filza, undecimus-sileo, activator). Requires matching entries under 'LSApplicationQueriesSchemes' in 'Info.plist' - the iOS build post-processor adds them automatically when the URL probe is enabled.
Suspicious path probe: Calls 'stat()' on the classic jailbreak artefacts (/Applications/Cydia.app, /Applications/Sileo.app, /Library/MobileSubstrate, /usr/sbin/sshd, /etc/apt, /private/var/lib/apt, ...) and the modern rootless prefixes used by Dopamine, palera1n, and XinaA15 (/var/jb, /var/jb/Applications/Sileo.app, /var/jb/usr/lib/libhooker.dylib, ...).
Sandbox violation probe: Attempts to create a file at '/private/jailbreak-probe-gups.txt'. Sandboxed iOS apps cannot write outside their container; success means the sandbox is not enforced. The file is deleted immediately to leave no trace.
fork() probe (opt-in): Resolves 'fork' at runtime via 'dlsym' and invokes it. Sandboxed apps cannot fork - a positive child PID is a strong jailbreak signal. Disabled by default because the symbol can be flagged by App Store static analysis even when never reached at runtime.
DYLD injection probe: Inspects the 'DYLD_INSERT_LIBRARIES' and 'DYLD_FORCE_FLAT_NAMESPACE' environment variables. iOS strips both for sandboxed apps; a populated value indicates runtime library injection.
Suspicious dylib probe: Walks '_dyld_get_image_name' and reports the first loaded image whose name contains a known tweak framework substring (MobileSubstrate, CydiaSubstrate, libsubstitute, libhooker, FridaGadget, frida-agent, SSLKillSwitch, cycript, ...).
Every probe is individually togglable from the global AntiCheat settings, and the path / dylib lists can be extended at runtime without recompiling the native plugin.
Observed Subject
The detector does not observe any monitor. It runs an on-demand scan when 'ManualScan()' is invoked or, if enabled, automatically during 'Start' and on a configurable interval.
Status
When jailbreak evidence is found, the detector notifies its observers with an IOSJailbreakDetectionStatus, which implements IIOSJailbreakDetectionStatus (and therefore IDetectorStatus):
public struct IOSJailbreakDetectionStatus : IIOSJailbreakDetectionStatus
{
// Probability that the detection is a false positive, in the range [0.0, 1.0].
public float PossibilityOfFalsePositive { get; }
// The threat rating reported with this detection.
public uint ThreatRating { get; }
// The type of jailbreak evidence detected on iOS.
public EIOSJailbreakType JailbreakType { get; }
// A short, human-readable string describing what triggered the detection.
public string Evidence { get; }
}
- Evidence: For example the matching path, URL scheme, or loaded dylib name.
The JailbreakType can be:
public enum EIOSJailbreakType : byte
{
UNKNOWN = 0, // Evidence could not be classified.
URL_SCHEME = 1, // A jailbreak URL scheme returned true from canOpenURL.
SUSPICIOUS_PATH = 2, // A path typical for a jailbreak was found on the device.
SANDBOX_VIOLATION = 3, // A file could be created outside the app sandbox.
FORK_SUCCESS = 4, // fork() returned a valid child PID.
DYLD_INJECTION = 5, // DYLD_INSERT_LIBRARIES / DYLD_FORCE_FLAT_NAMESPACE is populated.
SUSPICIOUS_DYLIB = 6 // A loaded dyld image matches a known tweak framework substring.
}
The detector dedupes by JailbreakType for the lifetime of the game session, so a recheck that matches the same category does not fire the punisher chain a second time.
Threat rating and false positives
- PossibilityOfFalsePositive: default
0.01(range 0-1). Low, because every probe checks for evidence that has no legitimate cause on a stock iOS device. - ThreatRating: default
500(recommended 500).
Configuration
- Is Active (
isActive, bool, default true) - whether the detector is active and watching. - Possibility Of False Positive (
possibilityOfFalsePositive, float, default 0.01, range 0-1). - Threat Rating (
threatRating, uint, default 500). - On Cheating Detection Event (
OnCheatingDetectionEvent) - a UnityEvent raised on every detection. - Check Only On Game Start (
CheckOnlyOnGameStart, bool, default false) - run the scan only once on start; disable to also run a periodic recheck. Recommended false, because a tweak framework can be loaded at any time on a jailbroken device. - Recheck Interval For Possible Cheating (
RecheckIntervalForPossibleCheating, float, default 30, range 0.1-600) - interval in seconds between scans.
Which probes run is configured in the global iOS project settings (see 'Configure iOS Settings' below). In the Unity editor and Development Builds the scan only runs when IOS_Enable_Development is enabled.
Supported Platforms
The detector is available on iOS player builds. In the Unity Editor and on every non-iOS platform the detector self-disables; in the editor it can be force-enabled for testing via 'IOS_Enable_Development' in the global AntiCheat settings (still requires building to a device for real scans, because the no-op probe is used in the editor).
Requirements
The detector requires the native plugin 'com.gups.anticheat' to be present in 'Assets/GUPS/AntiCheat/Plugins/iOS/'. It ships with the package, so no manual setup is needed in most cases.
Important
The plugin is a dynamic framework. Select 'com.gups.anticheat' in the Project window and, in the iOS plugin import settings, make sure "Add to Embedded Binaries" is enabled. If it is linked but not embedded, the app crashes at launch. No extra Apple frameworks need to be added: the ones the plugin uses ('UIKit' and 'Foundation') are already part of Unity's default iOS frameworks.
The iOS post-process build step ('PostProcessIOSBuild.cs') patches the generated 'Info.plist' on every iOS build and adds the URL schemes the detector probes to 'LSApplicationQueriesSchemes' (cydia, sileo, zbra, filza, undecimus-sileo, activator). Without these entries, 'canOpenURL' silently returns false on iOS 9 and later and the URL-scheme probe becomes a no-op.
False Positives
False positives are very unlikely on a stock device because every probe checks for evidence that has no legitimate cause:
- A stock device cannot resolve the jailbreak URL schemes (they are not registered).
- A stock device does not have files at any of the probed jailbreak paths.
- A stock device's sandbox blocks all writes outside the app container.
- A stock device strips 'DYLD_INSERT_LIBRARIES' before launching the app.
- A stock device never loads tweak frameworks.
The 'PossibilityOfFalsePositive' defaults to 0.01 to reflect the high confidence. The opt-in 'fork()' probe carries the same confidence as the rest because a positive return is a near-definitive signal.
How To Use
The usage is straightforward: attach an 'IOSJailbreakDetector' to a child GameObject of the 'AntiCheat-Monitor', configure the global iOS settings, and define a reaction to detected cheating.
Requirements
The detector requires the native plugin 'com.gups.anticheat' to be present in 'Assets/GUPS/AntiCheat/Plugins/iOS/' for real device scans, with "Add to Embedded Binaries" enabled (see the 'Requirements' section above). Without the plugin the binding fails gracefully and the detector logs a warning instead of crashing.
Add Detector Component
Manual
Add the 'IOSJailbreakDetector' MonoBehavior from the 'GUPS.AntiCheat.Detector.IOS' namespace to your 'AntiCheat-Monitor' GameObject, or better, to a child GameObject.

Add the 'IOSJailbreakDetector' as a Component.
Prefab
There is also a prefab, including the detector, which you can directly attach as a GameObject to the 'AntiCheat-Monitor':
- 'Assets/GUPS/AntiCheat/Resources/Prefabs/Detectors/iOS Jailbreak Detector.prefab'
Settings
After attaching the 'IOSJailbreakDetector' MonoBehavior to a GameObject, you will see the following in the inspector:

The settings of the 'IOSJailbreakDetector' Component.
- General Settings: Define here whether the detector should be active.
- Threat Rating Settings: Define here the severity of the detected cheating and the false-positive likelihood.
- Observable Settings: Add here callbacks invoked when cheating is detected.
- Jailbreak Settings: Set whether the scan runs once on Start and/or repeats on a configurable interval.
Runtime
On Start (and on the configured interval), the detector runs every probe enabled in the global settings and notifies observers for each previously unseen 'JailbreakType'. You can also trigger 'ManualScan()' yourself.
Configure iOS Settings
Open 'Edit -> Project Settings -> GuardingPearSoftware -> AntiCheat' and switch to the 'iOS' tab.

In the AntiCheat Project Settings, configure the iOS jailbreak detection.
Use the following entries to control this detector:
- Enable in Development: 'IOS_Enable_Development'. Set to true to allow detection inside the Unity Editor and Development Builds. Off by default.
- Detect URL Schemes: 'IOS_DetectUrlSchemes'. Probe known jailbreak URL schemes via 'canOpenURL'. On by default.
- Detect Suspicious Paths: 'IOS_DetectSuspiciousPaths'. Scan the built-in and additional path list via 'stat()'. On by default.
- Detect Sandbox Violation: 'IOS_DetectSandboxViolation'. Attempt a write outside the sandbox. On by default.
- Detect fork(): 'IOS_DetectFork'. Probe whether 'fork()' returns a positive child PID. Off by default (opt-in). Note: this probe is currently disabled in the shipped build regardless of the setting, to keep the safe App Store baseline; it will be re-enabled in a future release.
- Detect DYLD Injection: 'IOS_DetectDyldInjection'. Inspect 'DYLD_INSERT_LIBRARIES' and friends. On by default.
- Detect Suspicious Dylibs: 'IOS_DetectSuspiciousDylibs'. Scan loaded dyld images for known tweak framework substrings. On by default.
- Additional Paths: 'IOS_AdditionalSuspiciousPaths'. Optional list of extra paths to 'stat()' in addition to the built-in list.
- Additional Dylibs: 'IOS_AdditionalSuspiciousDylibs'. Optional list of extra dylib name substrings to look for in the loaded image list.
Consume the detection in code
Besides the inspector event, you can subscribe your own observer. Every detector derives from ADetector and exposes Subscribe(IObserver<IDetectorStatus>), which returns an IDisposable you can dispose to unsubscribe. Cast the status to IOSJailbreakDetectionStatus to read the iOS-specific fields:
using System;
using GUPS.AntiCheat;
using GUPS.AntiCheat.Core.Detector;
using GUPS.AntiCheat.Detector.IOS;
using UnityEngine;
public class IOSJailbreakDetectionLogger : MonoBehaviour, IObserver<IDetectorStatus>
{
private void Start()
{
var detector = AntiCheatMonitor.Instance.GetDetector<IOSJailbreakDetector>();
detector.Subscribe(this);
}
public void OnNext(IDetectorStatus status)
{
if (status is IOSJailbreakDetectionStatus iosStatus)
{
Debug.LogWarning($"Jailbreak detected: {iosStatus.JailbreakType} " +
$"(threat={iosStatus.ThreatRating}, evidence={iosStatus.Evidence}).");
}
}
public void OnError(Exception error) { }
public void OnCompleted() { }
}
React On Cheating
When the detector is set up, you surely want to react to detected cheating.
Punisher
In general, any cheat detected is forwarded to the 'AntiCheat-Monitor', which calculates an overall threat level. Based on the threat level, you can apply punishments by using Punisher components added to a child GameObject of the 'AntiCheat-Monitor'.

The location of the built-in Punisher prefabs.
Inspector
You can set a callback in the Unity Inspector view of the detector. This callback is invoked as soon as the specific cheating is detected.
Code
If you would like to write a custom listener for the detector, you can attach an observer:
// Get the detector.
var detector = AntiCheatMonitor.Instance
.GetDetector<IOSJailbreakDetector>();
// Subscribe as observer and get notified on inconsistency.
detector.Subscribe(myObserver);
The detector also has an inherited property 'PossibleCheatingDetected' which is set to true once cheating has been detected.