Certificate Pinning Bypass on iOS and Android

Security testers can bypass certificate pinning in minutes using standard tools.

Staff Writer, Mobile & API Security · · 10 min read
Cover illustration for “Certificate Pinning Bypass on iOS and Android”
Mobile Offensive Security · October 11, 2026 · 10 min read · 2,289 words

Certificate pinning stops a man-in-the-middle attack by refusing any TLS connection where the server's certificate or public key doesn't match a value baked into the app. The app carries a pinned certificate, a public key, or a SPKI hash. That's the whole mechanism. It's a real defense, aimed at a real threat: an attacker on an untrusted network or a compromised network trying to slip in and read traffic.

It's also a defense aimed at casual interception, not at a tester with physical access to the device and a licensed copy of Burp Suite. Pinning does what it's supposed to do when a proxy tries to insert its own CA into the chain, even after that proxy's certificate has been installed on the device. The app checks the actual server certificate, sees it doesn't match the pin, and kills the connection before the proxy ever sees a request.

All three produce the same effective block.

This is where the problem starts for anyone running a mobile penetration test. Dynamic testing intercepts traffic, replays and modifies API calls, probes how authentication actually behaves, and finds the business logic flaws that live in the gap between what the app shows and what the server allows, and it depends entirely on being able to see and change network traffic. Pinning blocks that first step. Before a tester can test anything that matters, pinning has to come down.

The governing standard that defines what a real test of pinning looks like

OWASP's Mobile Application Security Verification Standard (MASVS) sets out what a mobile security test is supposed to cover, and it treats pinning as one layer in a broader defense, not a checkbox on its own. MASVS-NETWORK-2 requires that an app pin identity for every remote endpoint the developer controls, trusting specific CAs instead of the full default list of root CAs that ship with the OS or framework. The standard also draws a clear line between two different things: confirming pinning is present, which an automated scanner can do, and confirming that the pinning actually holds up against a Frida-based bypass attempt, which requires a human tester working on a real device. Those are two different signals, and only one of them tells you anything about resistance to attack. A pen test that meets MASVS at Level 2 claims the pin held while someone actively tried to tear it down, not merely that the app pins its certificates.

Defeating pinning with Frida and Objection on iOS and Android

For most production apps, a tester gets past certificate pinning in a few minutes, using two tools: Frida and Objection. That speed is the single most important fact to understand about pinning as a control, because it sets the baseline every harder case gets measured against.

Frida is a dynamic instrumentation toolkit. It attaches to a running process and hooks any function inside it, including the TLS validation routines that check certificates. Frida doesn't care what language the app is written in or what framework it runs on. If it can attach to the process, it can intercept the function call before the app ever acts on the result.

Objection is built on top of Frida and ships with pre-built scripts aimed at the most common pinning implementations: OkHttp3, TrustKit, Retrofit, and iOS's URLSession.

On iOS, when Objection's generic hooks don't land, the standard move is a custom Frida script targeting the trust evaluation functions directly. Hooking SecTrustEvaluate from the Security framework means replacing it with a NativeCallback that writes a passing result and returns 0. For iOS 12 and later, the equivalent target is SecTrustEvaluateWithError, hooked with a NativeCallback that clears the error pointer and returns true. The script gets launched like this:

Android's newer versions complicate the Java-layer approach. Android's TLS stack runs on Conscrypt, a Java security provider backed by BoringSSL, and apps using the platform stack pin through Conscrypt's OpenSSLSocketImpl. Standard Frida scripts aimed at Java-layer TLS methods can miss this entirely on Android 15. Some apps add a custom X509TrustManager on top, so that has to be hooked as well.

There's also a path that doesn't touch Frida. Decompile the APK with apktool, replace network_security_config.xml with a permissive version that trusts user-installed CAs, recompile, and re-sign the package. It's slower and entirely static, but it works without any runtime tooling.

Where the standard bypass fails

Nine of the 28 apps in that sample resisted the single-command Objection bypass, and what separates them from the other 19 tells you something real: implementation quality sets bypass difficulty, and bypass difficulty is what a serious test is supposed to measure and report.

Some of those apps move their pinning logic into native code, compiled into a .so library instead of living in Java or Kotlin. Native libraries compiled with commercial LLVM obfuscation push that reverse engineering burden even higher.

Xposed modules, a common alternative to Frida on Android, hit their limits here too. They work fine against library-level hooks but fail against custom TrustManagers with hardcoded pin checks, native C/C++ SSL pinning using BoringSSL callbacks, or apps that detect Xposed by inspecting the ClassLoader. On iOS, the move to SecTrustEvaluateWithError as the standard trust evaluation path means apps still using the older, deprecated SecTrustEvaluate behave differently from current ones, and apps built on Network.framework need hooks at a different layer than apps built on NSURLSession.

A practical heuristic follows: if Objection's standard commands fail and nothing resembling certificate validation logic appears through class-dump or jadx, the pinning almost certainly lives at the native code level. The real value for a client is a report that says how hard the pin was to break, where it lived in the code, and what effort it took, because that's the information a dev team can act on.

Flutter apps as a distinct bypass problem that standard tooling cannot solve

Flutter apps break every technique described so far, and they break it for a structural reason. Certificate validation never touches the system trust store. It happens entirely inside the Flutter engine's native BoringSSL layer. Every hook aimed at the system trust store is hooking nothing.

Flutter also runs its own Dart HTTP stack, dart:io HttpClient backed by BoringSSL, bypassing Java-level hooks completely. And because interception depends on the OS trust store accepting a proxy's CA, Burp Suite's CA installation, Fiddler's root proxy, and mitmproxy's transparent mode all fail for the same reason: there's no system-level trust decision for them to hijack.

The tool built specifically for this is reFlutter. Either way, the pinning check gets neutralized before the app ever runs.

The catch is that reFlutter finds its target through hardcoded byte patterns, and BoringSSL gets recompiled fresh with every new Flutter engine release. The fallback at that point is manual: use radare2 or Ghidra to find the function by its BoringSSL control-flow signature and patch it directly.

React Native and Xamarin raise the same kind of problem, since both use custom networking stacks that sidestep platform-level interception. The point for anyone hiring a tester is that Flutter isn't just a harder version of the standard case. Testing it at all requires familiarity with a completely different toolchain, and a tester equipped with nothing but Objection and off-the-shelf Frida scripts will either fail to see the traffic or walk away thinking the app is secure when it was never actually tested.

Testing on non-rooted and non-jailbroken devices using Frida Gadget injection

Everything described above assumes a rooted or jailbroken test device, and treating that as a requirement understates how real the threat is. Frida Gadget injection runs on unmodified, stock production devices, removing root from the equation.

On iOS, the command objection patchipa injects a Frida gadget directly into the IPA, which then gets re-signed and sideloaded, no jailbreak required anywhere in the process.

Android has its own version of this same caveat. A physical device rooted with Magisk is the more reliable approach in those cases.

The threat-modeling consequence is direct. If a tester can get past pinning on a device with no root and no jailbreak, an attacker with nothing more than physical access to a stolen or borrowed phone can do the same thing. The vulnerability was never limited to jailbroken-device scenarios, and treating it that way understates who can actually exploit it.

What becomes visible once pinning is defeated

Breaking pinning doesn't find a vulnerability by itself. It opens the window that the real vulnerabilities sit behind, and those vulnerabilities almost always live on the backend, not inside the pinning code the tester just spent hours defeating. Once a server trusts the connection, whatever that server does wrong becomes visible.

The findings that come out of this stage tend to be serious ones: authentication tokens that never expire, session identifiers predictable enough to guess, and session fixation bugs. Broken Object Level Authorization, or BOLA, appears constantly once traffic is readable: an API endpoint lets one user reach or alter another user's data because the server never checks whether the requester actually owns the object being requested. If the app's interface hides an admin function from a standard account, but the API quietly executes that function anyway when called directly, that's a critical finding no matter how well the pinning held up.

Authorization decisions made purely on the client side turn up the same way. The app enforces a role check locally and assumes the server will enforce the same rule, but once traffic is visible a tester can rewrite the request and find out what the server actually allows. Insecure local storage and keychain misuse get confirmed in context here too, and weak or misused cryptography, including key material sent over a channel that looked protected, becomes visible once the traffic itself is readable.

Mutual TLS adds one more wrinkle worth knowing. Every copy of the app carries the same certificate. A tester who extracts it once can reuse it anywhere.

Bypassing pinning matters because of what it exposes. The bypass itself proves nothing about the app's security. What it exposes, the broken authorization, the client-side trust assumptions, the shared certificates, is where the real risk sits, and none of it is visible until the pin comes down.

Why pinning is worth implementing despite being routinely bypassed

None of this means pinning is pointless. It raises the cost of interception for casual attackers and automated scanning tools, even though skilled testers get past it routinely. How to pin, and what else to build around it, is what matters.

The cost difference is real and measurable. Objection's single command defeats most apps in minutes, but an app pinning at the native code level with commercial obfuscation layered on top demands serious reverse engineering time before anyone gets through. That gap, minutes against hours or days, is a genuine security benefit against attackers who don't have the skill or patience for the harder path.

OWASP's own guidance reflects how narrow pinning's upside actually is. OWASP's current guidance on certificate and public key pinning states that there is almost no situation where pinning should be considered, reflecting how often poor implementation turns pinning into an availability risk rather than a security win. Don't pin without controlling both the client and the server. Don't pin without a secure way to update the pinset. And think twice about pinning if updating that pinset means shipping an entirely new app release.

The apps that hold up under a determined bypass attempt combine pinning with native-code obfuscation, integrity checks, and anomaly detection working together. Pinning is one layer in that stack, not the whole wall.

For a test report, this sets the bar clearly. Confirming pinning exists tells a client almost nothing. Confirming that pinning held under active bypass attempts, documenting how much effort that took, and then reporting what sat underneath once the pin gave way: that's what a MASVS Level 2 assessment is supposed to deliver.

What this means when evaluating a mobile penetration test

A mobile pen test that skips certificate pinning bypass entirely, or that stops the moment the pin comes down without moving on to the backend API, has not covered the attack surface that actually matters to the business. Pinning bypass is a step in the process, not the deliverable.

A buyer evaluating a proposed test should ask whether the tester performs dynamic analysis on the app while it's running, because static analysis of the binary alone misses authentication bypass, business logic flaws, and broken access control, all of which only appear when the app is actually talking to a server. The scope should cover both the client-side app and the backend API it calls, since an assessment that only looks at the client misses the half of the attack surface where the more serious findings tend to live. The tester should have real, active experience on both iOS and Android, not just one, because the toolchains, the vulnerability patterns, and the testing approach differ enough between the two platforms that expertise in one doesn't transfer automatically to the other. If the app runs on Flutter, React Native, or Xamarin, the tester needs specific experience bypassing pinning on that framework, since the standard Frida-and-Objection toolkit fails against all three for the reasons already covered. And every finding in the report should come with a working proof of exploitability, not a theoretical description of what could go wrong.

None of this conflicts with passing an audit. A mobile pen test that covers MASVS Level 2 requirements, documents how pinning actually held up under attack, and backs its backend findings with working exploits satisfies the auditor and reflects the real threat model at the same time. Pinning bypass was never the finish line. It is the point where the actual test of the application finally begins.

More in Mobile Offensive Security