Security

    React Native SSL Pinning Bypass (Android)

    A React Native Android app's SSL pinning enforced in the native OkHttp layer being hooked on a rooted device while a proxy reads the traffic.

    In a React Native app on Android, SSL pinning usually lives in the native networking layer rather than in your JavaScript, because React Native's network calls run through OkHttp under the hood. So pinning is typically implemented with OkHttp's CertificatePinner, a library like TrustKit for Android, or a React Native pinning package that configures the same native path. That matters for testing, because a bypass on a device you control targets the native OkHttp trust check, not the JavaScript, forcing the check to pass. On a normal device, pinning protects your users from network interception, but a tester on a rooted device can defeat it, so understand where your pin lives, test your own app, and anchor real trust server-side.

    Short answer

    React Native pins at the native OkHttp layer on Android, so testing and bypass target that layer, not JavaScript. Per the OkHttp project, pinning is done with CertificatePinner in the native HTTP client React Native uses, and libraries like TrustKit for Android sit over the same path. On a rooted device, a tester hooks the native trust check to make pinning pass, which is possible because it is a client-side control, per the OWASP MASVS. Pinning protects users on healthy devices from interception, but not your API from the device owner. Know where your pin lives, test your own app, pin robustly, and enforce trust server-side with attestation like Play Integrity.

    Where React Native pins on Android: OkHttp and TrustKit

    The first thing to understand is that React Native's networking on Android goes through OkHttp, so pinning lives there rather than in your JavaScript. The most direct approach is OkHttp's CertificatePinner, which pins the server's public key or certificate at the native HTTP client level, so every request React Native makes is checked against the pin. Because this is where the actual TLS trust decision happens, it is where pinning is enforced and where testing has to look.

    TrustKit for Android is a common library layered on this, providing a configurable pinning implementation over the platform's networking, and there are React Native packages that expose pinning to JavaScript while configuring the same native path underneath. The practical point is that whichever you use, the enforcement is native, and a JavaScript-level pin still resolves to a native trust check. So to test your app's pinning, you look at the OkHttp or TrustKit configuration and the native trust evaluation, not at the JavaScript that calls fetch, because that is where the pin is actually applied and where it can be defeated.

    Why React Native pinning is bypassable

    React Native pinning on Android is bypassable for the same structural reason all client-side pinning is: the check runs as code on a device the attacker can control. The OkHttp or TrustKit trust evaluation ends in a decision about whether a certificate is acceptable, and on a rooted or instrumented device that decision can be hooked and forced to return acceptable, so the app proceeds as if the pin matched. Nothing about React Native changes this; it only changes where the check lives, which is native rather than in JavaScript.

    This is why OWASP treats pinning as a control that raises cost rather than a boundary. It increases the effort to intercept your traffic, which deters casual interception on a normal device, but it cannot stop a determined attacker who owns and has rooted the device from defeating the native check. Understanding that the bypass is possible, and that it targets the native OkHttp layer, tells you how much to rely on pinning: a lot for protecting ordinary users on healthy devices from network attackers, and not at all against a device owner who wants to see their own traffic.

    How a bypass targets the OkHttp check

    A tester bypasses React Native pinning on Android by hooking the native trust evaluation so it accepts any certificate, and knowing the target helps you understand the limit rather than providing a recipe. Because pinning runs in OkHttp or TrustKit, instrumentation such as Frida or Objection attaches to the running app and intercepts the certificate-check method in that native layer, making it return success regardless of the real certificate, after which an intercepting proxy can read the traffic. Objection includes built-in support for disabling common pinning implementations.

    The key defensive insight is that the hook happens where the pin is enforced, in the native OkHttp path, so a React Native JavaScript pin offers no extra protection: it still funnels into a native check that can be hooked. This is the same class of bypass as native Android or iOS pinning, applied to the layer React Native uses. Off-the-shelf tooling handles it, which is precisely why a client-side pin, wherever it sits in the stack, is not a boundary. It confirms your traffic is not intercepted by an outsider on a normal device, and nothing more against a rooted one.

    Testing your own app responsibly

    Testing whether your React Native pinning holds is a legitimate exercise you do only against your own app, on a device you own. Use a dedicated rooted test device or emulator that holds no personal data, install your own app build, attach Frida or Objection to hook the OkHttp or TrustKit trust check, and route the traffic through an intercepting proxy to confirm whether pinning can be disabled. Seeing your own traffic appear in the proxy after the hook tells you the pin is client-side and defeatable, which it always is.

    Keep the exercise bounded. Only instrument applications you have the right to test, keep the rooted environment isolated from personal accounts and production, and record findings so they inform your design. This mirrors how OWASP MASTG frames network and resilience testing: a controlled check of whether pinning behaves as intended and where its limits are. The goal is to confirm pinning works against ordinary interception on a normal device and to understand that a rooted attacker can defeat it, so you know what to protect elsewhere.

    What pinning protects and what it does not

    Being precise about what React Native pinning protects prevents misusing it. Pinning protects your users on healthy devices from a network attacker intercepting their traffic, for example someone on a hostile network with a rogue trusted certificate, which the pin rejects. That is a real threat, so pinning the OkHttp layer is worthwhile and does its job for the ordinary users who make up almost all of your audience.

    What it does not protect is your API from the owner of the device. A user who controls their device can hook the native check and observe the traffic their own app sends, so pinning is not an anti-reverse-engineering measure or a way to keep your API private from your own users. Designing as if pinning makes the client trustworthy is the mistake, because a rooted user defeats it. The correct model is that pinning secures the channel against outsiders while the device owner can always see their own traffic, so anything that must be protected from that user has to live server-side.

    Remediation: robust pinning and server-side trust

    Remediation has two parts: implement pinning well, and never rely on it alone. Pin to the public key rather than a leaf certificate so rotation is manageable, include backup pins so a certificate change does not break the app, and configure your OkHttp or TrustKit pinning carefully so it actually covers all your endpoints. These steps make pinning effective and reliable for legitimate users and raise the effort to bypass it, which is the realistic goal.

    The more important half is server-side trust. Because a determined user can defeat client pinning, the server must authenticate and authorize every request rather than trusting the client because pinning is present, and sensitive operations should be gated on server-side checks. For stronger assurance that a request comes from your genuine, unmodified app, add Google's Play Integrity, whose verdict is validated on your server and is far harder to forge than a client-side pin. Combine robust OkHttp pinning for channel protection with server-side authorization and attestation for real trust, and design as if the client may be compromised.

    Where the pin lives

    Knowing where pinning is enforced tells you where to test and what a bypass targets. The table below maps the approaches.

    Pinning approachWhere it is enforcedWhat a bypass targets
    OkHttp CertificatePinnerNative OkHttp clientThe certificate-check method
    TrustKit for AndroidNative, over OkHttpThe native trust evaluation
    React Native pinning packageJavaScript configuring a native pathThe underlying native check
    Server-side attestationYour serverNot hookable on the client

    Read the table top to bottom: every client-side row resolves to a native check that can be hooked on a rooted device, while only the server-side row is beyond the device owner's control.

    Hardening checklist

    Working through these steps keeps pinning effective while putting real trust server-side. The checklist below covers them.

    StepActionDone?
    Know where you pinIdentify OkHttp, TrustKit, or a JS package[ ]
    Test on your own appRooted device and a proxy you own[ ]
    Pin robustlyPublic-key pins with backup pins on all endpoints[ ]
    Do not rely on pinning aloneAuthorize every request server-side[ ]
    Add attestationPlay Integrity for sensitive operations[ ]
    Assume the owner sees trafficProtect the API server-side, not via pinning[ ]

    The step that changes your posture most is authorizing every request server-side, because it puts the deciding check where the device owner cannot hook it, unlike the native pinning above it.

    Assess your network posture

    Because transport security is more than a single pin, seeing your app's actual posture helps, including whether pinning is present and configured, whether cleartext is allowed, and how sensitive data travels. That is the input to hardening the channel and deciding what must be enforced server-side.

    A scanner like PTKD.com analyzes your build and reports issues such as weak transport security, allowed cleartext traffic, insecure data storage, and leaked keys by severity, mapped to OWASP MASVS, whose network category covers pinning and transport hardening. To be clear about the boundary: PTKD does not make pinning unbreakable, which nothing can on a rooted device, and it does not run a live bypass. It helps you see your transport and data-protection posture so you invest in the layers that actually carry trust.

    What to take away

    • React Native pins at the native OkHttp layer on Android, using CertificatePinner, TrustKit, or a package configuring the same path, so a JavaScript pin still resolves to a native check.
    • Pinning is bypassable because the native check runs on a device the attacker can control, and a bypass hooks the OkHttp or TrustKit trust evaluation, not the JavaScript.
    • Test this only against your own app on a rooted device you own, with a proxy, as a controlled OWASP-style network assessment.
    • Pinning protects users on healthy devices from interception, but it does not protect your API from a rooted device owner, so never treat it as anti-reverse-engineering.
    • Pin robustly with backup public-key pins, enforce trust server-side with authorization and Play Integrity, and review your posture with a tool like PTKD.com.
    • #react native
    • #ssl pinning
    • #android
    • #okhttp
    • #owasp masvs

    Frequently asked questions

    Where does React Native do SSL pinning on Android?
    In the native networking layer, because React Native's calls run through OkHttp. Pinning is typically done with OkHttp's CertificatePinner, a library like TrustKit for Android over the same path, or a React Native package that configures that native path while exposing pinning to JavaScript. The actual TLS trust decision happens natively, so a JavaScript pin still resolves to a native check, and testing looks at the OkHttp or TrustKit configuration, not the JavaScript that calls fetch.
    Can React Native SSL pinning be bypassed?
    Yes, on a device the tester controls. The OkHttp or TrustKit trust evaluation ends in a decision about whether a certificate is acceptable, and on a rooted or instrumented device that can be hooked and forced to return acceptable, so the app proceeds as if the pin matched. React Native does not change this; it only puts the check natively rather than in JavaScript. Pinning raises the cost of interception but is not a boundary against a rooted attacker.
    Does bypassing target OkHttp hooks or TrustKit?
    Whichever enforces the pin, and both are native. A tester using Frida or Objection attaches to the running app and hooks the certificate-check method in OkHttp, or the trust evaluation in TrustKit, making it return success regardless of the real certificate, after which an intercepting proxy reads the traffic. Objection includes built-in support for disabling common pinning implementations. Because the hook is at the native layer, a React Native JavaScript pin adds no extra protection.
    How do I test my own app's pinning responsibly?
    Only against your own app, on a device you own. Use a dedicated rooted test device or emulator holding no personal data, install your own build, attach Frida or Objection to hook the OkHttp or TrustKit trust check, and route the traffic through an intercepting proxy to see if pinning can be disabled. Only instrument apps you have the right to test, keep the environment isolated, and use the findings to decide what to protect server-side, per OWASP MASTG resilience testing.
    What does React Native pinning protect?
    Your users on healthy devices from a network attacker intercepting their traffic, for example someone on a hostile network with a rogue trusted certificate, which the pin rejects. That is a real threat, so pinning the OkHttp layer is worthwhile. What it does not protect is your API from the owner of the device, who can hook the native check and see their own traffic, so pinning is not anti-reverse-engineering or a way to keep your API private from your users.
    What is the durable defense if pinning is bypassable?
    Server-side trust. Because a determined user defeats client pinning, the server must authenticate and authorize every request rather than trusting the client, and sensitive operations should be gated on server-side checks. For stronger assurance that a request comes from your genuine, unmodified app, add Google's Play Integrity, whose verdict is validated on your server and is hard to forge. Combine robust OkHttp pinning for the channel with server-side authorization and attestation for real trust.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free