If I want my app to behave differently on a jailbroken iPhone, how would I go about determining this?
-
You are going to be following a moving target, but you might try following the progress of these resources to see how effective your technique is: - https://www.theiphonewiki.com/wiki/Bypassing_Jailbreak_Detection - https://www.theiphonewiki.com/wiki/XCon – Michael Bishop Apr 22 '16 at 14:50
16 Answers
It depends what you mean by jailbreak. In the simple case, you should be able to see if Cydia is installed and go by that - something like
NSString *filePath = @"/Applications/Cydia.app";
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
// do something useful
}
For hacked kernels, it's a little (lot) more involved.

- 3,288
- 20
- 12
-
18Wouldn't it be enough to look for _any_ file/dir outside your sandbox? Like /etc? – Rhythmic Fistman Aug 01 '09 at 04:53
-
62Note that not all users have Cydia installed -- this is not a good check, and you should rather check for something like /bin/bash that /all/ users /will/ have. – Grant Paul Feb 21 '10 at 07:03
-
2Where does apt store its info? Or could I just call a system() command and find out. I want to find out if they have certain apps, and if they have them, then restrict the app – conradev Mar 06 '10 at 20:16
-
@chpwn is var/cache/apt a jailbreak only folder, and would that be a good check? Because when I check for bin/bash, even non-jailbreak devices register as jailbroken. – Sam Spencer May 29 '12 at 21:52
-
2@RazorSharp At this point, almost all users do have Cydia. It's probably enough to check for that now. However, if you want a 100% reliable check, you'll want to use a kernel-based check as below. – Grant Paul Jun 01 '12 at 07:29
-
-
1FWIW the file checks are trivial to bypass. One can use mobilesubstrate to hook `fileExistsAtPath:` and make it return `NO` for the specific path you check. – toasted_flakes May 31 '14 at 10:41
-
-
This is not workable on xCon , Can advice more on how to do it. https://github.com/masbog/isJB/issues/1 have more indepth code than above but still fails for xCon , any leads. – codelover Mar 23 '17 at 09:19
-
This is a code that combine some answers I found for this need, and will give you much higher success rate :
BOOL isJailbroken()
{
#if !(TARGET_IPHONE_SIMULATOR)
if ([[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/Cydia.app"] ||
[[NSFileManager defaultManager] fileExistsAtPath:@"/Library/MobileSubstrate/MobileSubstrate.dylib"] ||
[[NSFileManager defaultManager] fileExistsAtPath:@"/bin/bash"] ||
[[NSFileManager defaultManager] fileExistsAtPath:@"/usr/sbin/sshd"] ||
[[NSFileManager defaultManager] fileExistsAtPath:@"/etc/apt"] ||
[[NSFileManager defaultManager] fileExistsAtPath:@"/private/var/lib/apt/"] ||
[[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://package/com.example.package"]]) {
return YES;
}
FILE *f = NULL ;
if ((f = fopen("/bin/bash", "r")) ||
(f = fopen("/Applications/Cydia.app", "r")) ||
(f = fopen("/Library/MobileSubstrate/MobileSubstrate.dylib", "r")) ||
(f = fopen("/usr/sbin/sshd", "r")) ||
(f = fopen("/etc/apt", "r"))) {
fclose(f);
return YES;
}
fclose(f);
NSError *error;
NSString *stringToBeWritten = @"This is a test.";
[stringToBeWritten writeToFile:@"/private/jailbreak.txt" atomically:YES encoding:NSUTF8StringEncoding error:&error];
[[NSFileManager defaultManager] removeItemAtPath:@"/private/jailbreak.txt" error:nil];
if(error == nil)
{
return YES;
}
#endif
return NO;
}

- 2,525
- 2
- 21
- 24
-
this is much better than others, but I will not try to write text files, this will slow down the performance. – Porizm Jan 05 '15 at 22:05
-
1@Porizm, this is just a combination off some answers I found. Some of them didn't work for me, but worked for others.. so with this code you don't take chances.. If you use this you can be 99% sure. Regarding the performance, you can run it only once at each run and save the answer somewhere, You don't have to run it each time.. – Yossi Jan 06 '15 at 08:59
-
3@yossi and porizm apple approved your app which contains the above code ? please reply – karthikPrabhu Alagu Feb 18 '15 at 07:24
-
4This method should be an inlined C function, *not* Objective-C. It's too easy to discover and bypass Objective-C methods, especially if you call it `isJailbroken` – progrmr Dec 02 '15 at 01:00
-
2
-
3@Lakshay I don't know.. You are more than invited to check and add here an answer :) – Yossi Jun 17 '16 at 03:06
-
Checking if the device can open `cydia://package/com.example.package` will provide a false-positive if the user has an app installed that conforms to `cydia://` scheme like InstantTV. – thattyson May 26 '20 at 15:49
+(BOOL)isJailbroken {
NSURL* url = [NSURL URLWithString:@"cydia://package/com.example.package"];
return [[UIApplication sharedApplication] canOpenURL:url];
}
Checking the file path /Applications/Cydia.app
is not allowed on a normal phone? I've never heard of Apple detecting this and rejecting an app for it, but Apple is unpredictable. Cydia has a URL scheme cydia:// which can be legally checked with UIApplication canOpenURL:

- 31,017
- 13
- 83
- 207

- 1,105
- 9
- 8
-
1This is a great way to check, and it does not go outside your sandbox. Sure, if the jailbreaker does not have Cydia installed, it will return NO, but I think most Jailbreaks install Cydia. – Wim Haanstra Feb 08 '13 at 08:06
-
-
9For iOS9.0+ you also need to add LSApplicationQueriesSchemes key in app plist. Otherwise canOpenURL will always return false. – David V Jan 16 '17 at 12:17
-
1This will provide a false-positive if the user has an app installed that conforms to cydia:// scheme like InstantTV. – thattyson May 26 '20 at 15:48
-
@thattyson thanks! I was looking to check why I was getting false positives – rickrvo May 28 '20 at 13:15
Checking if the kernel is broken isn't THAT much more involved.
Jailbreaking makes the kernel's signature check of signed code always report that code is signed correctly, unbroken phones cannot run code with a bad signature.
So, include a separate executable in the app with a bad signature. It could just be a 3-line program that has main() and a return value. Compile the executable without code signing (turn it off in Project Settings->Build) and sign it with a different key using the "codesign" commandline utility.
Have your app exec the separate executable. If your program can't get the return value when running the separate executable with the bad sig, it's definitely jailed. If the separate executable returns A-OK, the phone is definitely jailbroken.

- 792
- 5
- 4
-
14Can you get a (sub-)executable whose signature is invalid like that through the App Store? – fbrereto Apr 06 '10 at 22:28
-
36Perhaps things have changed but wouldn't executing a separate executable prevent you from being approved to the app store? – Peter Zich Jan 04 '11 at 22:47
-
4
-
Nobody is really going to stop you from writing a Mach-O to disk with an invalid signature. However, I disagree with the answer that checking that the kernel is broken isn't involved or that this is a definitive check by any means. – saagarjha Jun 04 '20 at 21:11
BOOL isJailbroken()
{
#if TARGET_IPHONE_SIMULATOR
return NO;
#else
FILE *f = fopen("/bin/bash", "r");
if (errno == ENOENT)
{
// device is NOT jailbroken
fclose(f);
return NO;
}
else {
// device IS jailbroken
fclose(f);
return YES;
}
#endif
}

- 55,009
- 24
- 135
- 201
-
That's a good solution, but xCon and other tools like it can easily bypass this check. So, I'm looking for a better solution. – Alexei Robsky Mar 05 '12 at 15:10
-
7@AlexeiRobsky there is no perfect solution. There will always be someone who will find a way to bypass your protection, it's just a fact. – Richard J. Ross III Mar 05 '12 at 15:33
I reworked in Swift 2.3 the solution provided by @Yossi
public static func jailbroken(application: UIApplication) -> Bool {
guard let cydiaUrlScheme = NSURL(string: "cydia://package/com.example.package") else { return isJailbroken() }
return application.canOpenURL(cydiaUrlScheme) || isJailbroken()
}
static func isJailbroken() -> Bool {
if isSimulator {
return false
}
let fileManager = NSFileManager.defaultManager()
if fileManager.fileExistsAtPath("/Applications/Cydia.app") ||
fileManager.fileExistsAtPath("/Library/MobileSubstrate/MobileSubstrate.dylib") ||
fileManager.fileExistsAtPath("/bin/bash") ||
fileManager.fileExistsAtPath("/usr/sbin/sshd") ||
fileManager.fileExistsAtPath("/etc/apt") ||
fileManager.fileExistsAtPath("/usr/bin/ssh") {
return true
}
if canOpen("/Applications/Cydia.app") ||
canOpen("/Library/MobileSubstrate/MobileSubstrate.dylib") ||
canOpen("/bin/bash") ||
canOpen("/usr/sbin/sshd") ||
canOpen("/etc/apt") ||
canOpen("/usr/bin/ssh") {
return true
}
let path = "/private/" + NSUUID().UUIDString
do {
try "anyString".writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding)
try fileManager.removeItemAtPath(path)
return true
} catch {
return false
}
}
static func canOpen(path: String) -> Bool {
let file = fopen(path, "r")
guard file != nil else { return false }
fclose(file)
return true
}

- 4,210
- 3
- 22
- 31
-
you done good job, but if you comment on those url's we can appreciate. – Naresh May 12 '23 at 09:06
-
-
Your code was not working in latest Xcode versions, can you update it. Thank you. – Naresh May 12 '23 at 10:40
You can detect if a device is JailBroken or not by checking for the following:
- Cydia is installed
- Verify some of the system paths
- Perform a sandbox integrity check
- Perform symlink verification
- Verify whether you create and write files outside your Sandbox
There is an open source library I created from various articles and books. Try it out on GitHub!

- 8,492
- 12
- 76
- 133

- 301
- 2
- 3
The most sophisticated method I know is using objc_copyImageNames()
function. It returns a list of currently loaded libraries and since most people have MobileSubstrate on jailbroken devices and most iAP crack tools depend on it, at least some MobileSubstrate libraries will show up.

- 1,181
- 8
- 15
-
Do you have any links on what MobileSubstrate/CydiaSubstrate libraries look like? I don't have a jailbroken phone to play around with so am driving "blind" and Google searches basically come up with your comment above. – chadbag May 20 '14 at 21:58
-
@chadbag I don't have one either but you can look for the `deb` file of MobileSubstrate, unpack it and blacklist (almost) all `.dylib`'s it packed. – Maxthon Chan May 22 '14 at 11:28
-
Thanks, I got some code figured out and I may add in some more stuff based on your comment. Many thanks! – chadbag May 22 '14 at 17:49
Please use following code for Swift 4 and above: Add the following code in the appdelegate:
private func getJailbrokenStatus() -> Bool {
if TARGET_IPHONE_SIMULATOR != 1 {
// Check 1 : existence of files that are common for jailbroken devices
if FileManager.default.fileExists(atPath: "/Applications/Cydia.app")
|| FileManager.default.fileExists(atPath: "/Library/MobileSubstrate/MobileSubstrate.dylib")
|| FileManager.default.fileExists(atPath: "/bin/bash")
|| FileManager.default.fileExists(atPath: "/usr/sbin/sshd")
|| FileManager.default.fileExists(atPath: "/etc/apt")
|| FileManager.default.fileExists(atPath: "/private/var/lib/apt/")
|| UIApplication.shared.canOpenURL(URL(string:"cydia://package/com.example.package")!) {
return true
}
// Check 2 : Reading and writing in system directories (sandbox violation)
let stringToWrite = "Jailbreak Test"
do {
try stringToWrite.write(toFile:"/private/JailbreakTest.txt", atomically:true, encoding:String.Encoding.utf8)
//Device is jailbroken
return true
} catch {
return false
}
}
else {
return false
}
}
Inside Appdelegate methods, write code as below
func applicationDidBecomeActive (_ application: UIApplication) {
if getJailbrokenStatus() {
let alert = UIAlertController(title: LocalizedKeys.Errors.jailbreakError, message: LocalizedKeys.Errors.jailbreakErrorMessage, preferredStyle: UIAlertController.Style.alert)
let jailBrokenView = UIViewController()
jailBrokenView.view.frame = UIScreen.main.bounds
jailBrokenView.view.backgroundColor = .white
self.window?.rootViewController = jailBrokenView
jailBrokenView.present(alert, animated: true, completion: nil)
}
if #available(iOS 11.0, *) {
if !UIScreen.main.isCaptured {
DispatchQueue.main.async {
self.blockImageView.removeFromSuperview()
}
}
}
}

- 1,095
- 12
- 18

- 81
- 1
- 4
-
self.blockImageView.removeFromSuperview() getting error, please suggest what to be done – Arshad Shaik Dec 22 '20 at 06:21
I am not aware of any "APIs" that exist for this. If there were, then a jailbreak-masking product would quickly cover them up.
As lots of people point out, it is a cat-and-mouse game. And after both players become expert, it all comes down to who gets the first move. (Person holding the device.)
I found many good suggestions for detecting jailbreak in Zdziarski's new book "Hacking and Securing iOS Apps". (Personally, I paid more for the O'Reilly eBook because they permit copy-and-paste.)
No, I am not affiliated with the publishers. But I did find it a good book. I don't like to just publish hackers' mistakes so they can fix them, so I thought I'd point to the book.

- 3,806
- 30
- 35
Try executing unsigned code through your application.
A jailbroken devices usually has the following characteristics:
- run unsigned code
- has Cydia installed
- has jailbreak files
- full r/w access to the whole filesystem
- some system files will have been modified (content and so sha1 doesn't match with original files)
- stuck to specific version (jailbreakable version)
Just checking file existence for jailbreak detection is doomed to fail. These checks are easy to bypass.

- 41
- 1
-
4Trying to execute unsigned code would make your app being rejected from the appstore – Frederic Yesid Peña Sánchez Sep 03 '13 at 18:11
Some common files to check for:
/Library/MobileSubstrate/MobileSubstrate.dylib
/Applications/Cydia.app
/var/cache/apt
/var/lib/apt
/var/lib/cydia
/var/log/syslog
/var/tmp/cydia.log
/bin/bash
/bin/sh
/usr/sbin/sshd
/usr/libexec/ssh-keysign
/etc/ssh/sshd_config
/etc/apt
Most check for Cydia related files.

- 6,982
- 9
- 45
- 80
What we did is, we already have an RSS feed to communicate with our users (Stocks Live), we put a news item that states something like this:
Some jailbroken devices have problems bla bla bla, we made a hack to solve those issues but we need to know if this a jailbroken device or not, press here so the app fixes the issue. If you ever return to normal, ie removed the jailbreak, press here.
Then you process the user interaction and do what is appropriate, like behaving different etc...
Try to find a file which cydia or jailbroken device create. Or try to write in a file outside the app's blackbox. If you succeed to do that, the device is compromised/jailbroken :)
- (BOOL)jailbroken
{
NSFileManager * fileManager = [NSFileManager defaultManager];
return [fileManager fileExistsAtPath:@"/private/var/lib/apt/"];
}

- 15,408
- 7
- 58
- 96
I'd suggest looking for files that aren't present on a "vanilla" iPhone. All jailbreak kits I've seen install ssh. That might be a good indicator of a jailbroken phone.

- 26,244
- 11
- 57
- 60
-
19ssh is never installed automatically, users must install it themselves. – Grant Paul Feb 21 '10 at 07:03
-
1I haven't really kept up with the jailbreak scene. But as I recall, when I wrote this (Jan '09), Ziphone and others installed ssh and the bsd subsystem by default. Perhaps that's no longer true. – Gordon Wilson Mar 04 '10 at 06:06
-
12trust me when i say that chpwn has kept up with the jailbreak scene. – Winfield Trail Jul 14 '11 at 00:45
Here's my solutions: Step 1
extension UIDevice {
func isJailBroken() -> Bool {
let cydiaPath = "/Applications/Cydia.app"
let aptPath = "/private/var/lib/apt/"
if FileManager.default.fileExists(atPath: cydiaPath) || FileManager.default.fileExists(atPath: aptPath) {
return true
}
return false
}
}
Step 2: Call it inside viewDidLoad()
inside your launch screen view controller(or whatever VC you are calling for the first time):
// show a blank screen or some other view controller
let viewController = UIDevice.current.isJailBroken() ? JailBrokenViewController() : NextViewController()
self.navigationController?.present(viewController, animated: true, completion:nil)

- 441
- 7
- 10