Certificate pinning bypass
When it applies
The app pins its server cert, so a normal MITM proxy (Burp/mitmproxy) can't decrypt its traffic — you get handshake errors and empty history. You need to test the backend, so the pin has to go.
Why it works
Pinning is enforced in the client you control. At runtime you can replace/neutralize the verification routine; statically you can patch it out. Either way the app then trusts your proxy's CA.
Method
- Install your CA first: add Burp/mitmproxy CA to the device (Android 7+ needs it as a
system cert, or use a
network_security_configon a repackaged app). - Runtime (fastest):
objection -g <pkg> explorethenandroid sslpinning disable(iOS:ios sslpinning disable), or a Frida script (frida-multiple-unpinning). - Static patch (when Frida is blocked):
apktool d, remove/patch theCertificatePinner/ TrustManager checks or swapnetwork_security_configto trust user CAs, rebuild + resign (apktool b,uber-apk-signer). - Confirm: traffic now appears decrypted in the proxy; proceed to backend testing.
Gotchas
- No traffic at all (not just pinning) can mean the app uses a non-HTTP protocol or a VPN — check.
- Some apps double-pin or detect Frida/root — combine root-detection bypass, or use static patching.
- iOS on a non-jailbroken device needs a repackaged/sideloaded app or a jailbroken test device.
Verify success
The proxy shows plaintext requests/responses from the app; you can now replay/modify them.
References
OWASP MASTG (network); objection & frida-multiple-unpinning; TrustKit/OkHttp docs.