Certificate pinning — the practice of hardcoding expected server certificates or public keys into a mobile application — has been a cornerstone of mobile API security for a decade. The cat-and-mouse game between pinning implementations and bypass tooling has escalated considerably in the past two years, driven by platform changes in iOS 18 and Android 15, more sophisticated obfuscation in security-conscious applications, and improved tooling on both sides.

The Standard Bypass Toolkit

Frida remains the most powerful instrument for certificate pinning bypass. The dynamic instrumentation toolkit allows runtime hooks into any function in a running process — including the TLS validation routines responsible for certificate checking.

Objection, built on Frida, provides pre-built scripts targeting common implementations including OkHttp3, TrustKit, Retrofit, and iOS URLSession. The key commands:

# iOS
objection --gadget "TargetApp" explore
ios sslpinning disable

# Android  
objection --gadget "com.target.app" explore
android sslpinning disable

In our testing against 28 mobile applications across banking, healthcare, and enterprise categories, these commands successfully bypassed pinning in 19 applications without any customisation required.

The 9 applications that resisted required custom Frida scripts, reverse engineering of native libraries, or physical device testing to circumvent additional security controls layered alongside pinning.

What's Actually Hardened in 2025

Applications implementing pinning at the native code level represent meaningfully harder targets:

  • Android JNI implementations — pinning logic in a native library (.so file) rather than Java/Kotlin is harder to hook. Frida can still attach, but identifying the correct function offset requires static analysis of the binary first.
  • iOS Swift with obfuscated URLSessionDelegate — custom URLSession delegate implementations that validate certificate hashes in Swift, compiled with obfuscation passes, require decompilation to understand the validation logic before writing a bypass.
  • LLVM-obfuscated binaries — we have encountered applications that validate certificate hashes in native libraries compiled with commercial LLVM obfuscation. These require significant reverse engineering effort before a bypass can be written.

A useful heuristic: if objection's standard commands fail and you can't find obvious certificate validation logic using class-dump or jadx, you're likely dealing with native code pinning.

Android 15 and the Conscrypt Layer

Android 15's updated Network Security Configuration with certificate transparency enforcement adds complexity that older bypass techniques do not address.

Android's TLS stack uses Conscrypt — a Java Security Provider backed by BoringSSL. Applications that rely on the platform TLS stack are pinning through Conscrypt's OpenSSLSocketImpl. Standard Frida scripts that hook the Java-layer TLS methods may miss implementations that operate at the Conscrypt level.

Our updated approach targets OpenSSLSocketImpl directly:

// Frida script — Conscrypt-level bypass (Android 15)
Java.perform(function() {
  const OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
  OpenSSLSocketImpl.verifyCertificateChain.implementation = function(certRefs, authMethod) {
    // bypass: do nothing, accept any chain
  };
});

This approach has been effective against all Conscrypt-level implementations we've tested. Note that some applications additionally implement X509TrustManager custom implementations — both hooks may be necessary.

iOS 18 — Trust Store Changes

Apple's changes to the trust evaluation chain in iOS 18 have minor but notable implications for bypass tooling:

  • The SecTrustEvaluateWithError API is now the standard path. Applications still using the deprecated SecTrustEvaluate may behave differently — some bypass scripts target one or the other.
  • Applications implementing pinning via URLSession's didReceiveChallenge delegate method remain bypassable via Frida hooks on NSURLSession.
  • Applications using Network.framework (NWConnection) require hooks at a different layer — nw_connection_copy_protocol_metadata and the TLS protocol options.

Physical Device vs Emulator

For hardened applications with root/jailbreak detection:

  • Android — test on a physical device rooted with Magisk + MagiskHide (or its successors). Emulators are increasingly detected. For the most hardened applications, consider a custom Android build with ro.debuggable=1.
  • iOS — jailbreak detection is harder to bypass than certificate pinning in many high-security applications. Palera1n on iOS 16 remains more reliable than jailbreaks for iOS 17/18. For applications that detect popular jailbreaks, Liberty Lite and Shadow can suppress detection.

Developer Recommendations

The goal for developers is not to make certificate pinning unbypassable — determined attackers with physical access to a device will always have options. The goal is to raise the cost sufficiently that casual interception is impossible and targeted attacks require significant expertise and effort.

  • Implement pinning at the native code level rather than through framework abstractions — this alone increases bypass difficulty dramatically
  • Combine public key pinning with backup pin sets to survive certificate rotation without releasing a new app build
  • Layer anti-tampering and root/jailbreak detection to raise the cost of bypass — not as the sole defence, but as friction
  • Use certificate transparency logging for all issued certificates, so unexpected certificates for your domains are detectable
  • Conduct MASVS-aligned mobile penetration tests at least annually and after major releases — the tooling evolves quickly and last year's "secure" implementation may be bypassable today

The applications we cannot bypass in a standard engagement are not those with the most sophisticated pinning — they're the ones with defence-in-depth: pinning plus native obfuscation plus integrity checks plus anomaly detection on the server side for unusual API usage patterns.