
SSL pinning on iOS presents a different set of challenges compared to Android. Apple's ecosystem, combined with strict code signing and sandboxing, means testers need a jailbroken device and a different toolchain to instrument running applications. For penetration testers and mobile security researchers, understanding how iOS apps implement certificate pinning, and how to defeat it, is essential before any meaningful traffic analysis can begin.
This guide covers the full workflow: identifying pinning implementations in iOS apps, preparing a jailbroken testing environment, and using Frida along with supporting tools to intercept HTTPS traffic that would otherwise be blocked.
iOS apps typically implement certificate pinning through one of a few common mechanisms:
NSURLSession delegate methods that validate server trust manuallySecTrustEvaluate calls in the app's TLS validation logicUnlike Android, where Java reflection makes classes easy to enumerate, iOS apps compiled in Swift often strip symbol names, making static analysis and hooking noticeably harder. This is why dynamic instrumentation with Frida has become the standard approach for iOS pinning bypass work.
Before any bypass attempt, you need a properly configured testing device. SageFox Cybersecurity's mobile assessment labs standardize on jailbroken physical devices rather than simulators, since many pinning and anti-tampering checks behave differently or are skipped entirely in simulator environments.
Add the Frida repository to Sileo or Cydia, then install the re.frida.server package. Once installed, verify it is running.
bash
ssh root@<device-ip>
ps aux | grep frida-serverbash
pip install frida-tools frida
frida-ps -UIf your device appears in the process list output, the connection between your host and the jailbroken device is working correctly.
Before writing a hook, it helps to understand what you are targeting. Pulling the IPA and inspecting the binary gives you a starting point.
bash
ideviceinstaller -l
scp root@<device-ip>:/private/var/containers/Bundle/Application/<app-guid>/AppName.app ./AppName.appbash
strings AppName.app/AppName | grep -i "pinning"
strings AppName.app/AppName | grep -i "SecTrustEvaluate"
strings AppName.app/AppName | grep -i "AFSecurityPolicy"If you see references to AFSecurityPolicy, the app likely uses AFNetworking's pinning implementation. If SecTrustEvaluate appears frequently alongside custom class names, the app has rolled its own validation logic, which typically requires a more tailored hook.
Before writing custom Frida scripts, many testers start with SSL Kill Switch 3, a jailbreak tweak specifically built to disable pinning at the system level by hooking common validation APIs across the OS.
Install it through Sileo or Cydia, enable it in the tweak's settings panel, and respring the device.
bash
killall -HOLD SpringBoardThis approach works well for apps using standard NSURLSession or AFNetworking pinning, but it often fails against apps with custom, hardened pinning logic. That is where targeted Frida scripting becomes necessary, and it is the layer where SageFox Cybersecurity's mobile testers spend most of their engagement time, since real banking and fintech apps almost never rely on default pinning behavior alone.
For apps using standard NSURLSession delegate-based validation, you can hook the URLSession:didReceiveChallenge:completionHandler: delegate method directly.
javascript
if (ObjC.available) {
var className = "NSURLSession";
var hook = ObjC.classes[className];
Interceptor.attach(ObjC.classes.NSURLConnection["- connection:willSendRequestForAuthenticationChallenge:"].implementation, {
onEnter: function (args) {
console.log("[*] NSURLConnection auth challenge intercepted");
var challenge = new ObjC.Object(args[3]);
var sender = challenge.sender();
sender.useCredential_forAuthenticationChallenge_(
ObjC.classes.NSURLCredential.credentialForTrust_(challenge.protectionSpace().serverTrust()),
challenge
);
}
});
}Run this against the target application using Frida's spawn mode so the hook is active before the app initializes its networking stack.
bash
frida -U -f com.target.bundleid -l nsurlsession_bypass.js --no-pauseApps built with AFNetworking often expose a SecurityPolicy class that controls pinning behavior. Hooking its evaluation method directly disables the check.
javascript
if (ObjC.available) {
var AFSecurityPolicy = ObjC.classes.AFSecurityPolicy;
Interceptor.attach(AFSecurityPolicy["- evaluateServerTrust:forDomain:"].implementation, {
onLeave: function (retval) {
console.log("[+] AFSecurityPolicy evaluateServerTrust bypassed");
retval.replace(0x1);
}
});
}For Alamofire-based apps, the equivalent target is usually the ServerTrustManager or PinnedCertificatesTrustEvaluator class, depending on the version. Since Alamofire is written in Swift, symbol names are frequently mangled, so confirming the exact method signature with a tool like Frida's ObjC.classes enumeration before writing the hook saves significant trial and error.
bash
frida -U -f com.target.bundleid -e "console.log(JSON.stringify(Object.keys(ObjC.classes).filter(c => c.includes('Trust'))))"When an app implements custom validation logic that calls into Apple's Security framework directly, hooking SecTrustEvaluateWithError or the legacy SecTrustEvaluate function at the native level is the most reliable approach.
javascript
var secTrustEvaluate = Module.findExportByName("Security", "SecTrustEvaluateWithError");
Interceptor.attach(secTrustEvaluate, {
onLeave: function (retval) {
console.log("[+] SecTrustEvaluateWithError forced to true");
retval.replace(0x1);
}
});This hook works regardless of which Swift or Objective-C library sits above it, since every pinning implementation on iOS eventually calls down into this framework at some point during the trust evaluation chain.
Once your hooks are active, confirm success by checking your intercepting proxy.
If the app connects normally and traffic populates in your proxy, the bypass is successful. If you see TLS handshake failures or the app immediately closes the connection, there may be a secondary pinning check running in a background thread or a native library not yet covered by your current hooks.
Many production apps run jailbreak detection before any networking code executes. Pairing your pinning bypass script with a jailbreak detection bypass script, hooking common checks like fork(), NSFileManager fileExistsAtPath:, and known jailbreak file paths, is often required together.
This can happen if the app has anti-debugging protections. Try attaching to the process after launch instead of spawning it directly.
bash
frida -U AppName -l bypass.jsConfirm you are targeting the correct class and method by re-checking symbol names for that specific app version, since minor updates frequently change internal class structures, especially in Swift-based apps recompiled with newer Xcode toolchains.
Methodology and patience matter more than any single script here. SageFox Cybersecurity's mobile assessment team builds and maintains custom Frida hook libraries specifically for iOS, since client apps frequently combine multiple pinning layers with jailbreak detection to slow down exactly this kind of analysis.
Bypassing SSL pinning on iOS requires a jailbroken environment, a solid understanding of how the target app validates server trust, and the ability to write targeted Frida hooks at the Objective-C, Swift, or native Security framework level. Generic tweaks like SSL Kill Switch cover the easy cases, but real-world assessments almost always require custom scripting against AFSecurityPolicy, Alamofire's trust evaluators, or raw SecTrustEvaluateWithError calls.
If your organization needs a thorough review of how your iOS application handles certificate validation, network security, and anti-tampering controls, SageFox Cybersecurity's mobile penetration testing team can uncover these gaps before they become real incidents, with a clear remediation roadmap your development team can act on right away.