Security · TLS

SSL pinning in React Native: 4 approaches, 3 of them broken

Published June 3, 2026 · 9 minute read
TL;DR

SSL pinning protects against TLS interception. Done wrong, it bricks your app the day your TLS certificate rotates. The wrong-vs-right is mostly about pinning the public key (not the certificate) and embedding backup pins.

Most consumer apps don't need pinning. The operational risk usually outweighs the threat-model benefit. Banking, healthcare, and regulated payments are the cases where it's worth it.

If you do pin, use native config (App Transport Security on iOS, Network Security Config on Android). Pin the public key. Always carry a backup pin. Plan rotation.

SSL pinning sounds like a security upgrade. It's also a famous foot-gun. A cert rotates, your app stops working for everyone simultaneously, and you find out the urgent app update needs App Store review.

This post is the four common approaches in React Native, why three of them are usually broken in some way, and the operational pattern that makes pinning a real security control instead of a self-imposed outage.

On this page
  1. What pinning is and isn't
  2. When to actually pin
  3. Certificate pinning vs public key pinning
  4. Approach 1: Native config (recommended)
  5. Approach 2: TrustKit (iOS)
  6. Approach 3: react-native-ssl-pinning
  7. Approach 4: Custom native module
  8. Pin rotation strategy
  9. Failure modes
  10. FAQ

What pinning is and isn't

Pinning narrows TLS trust. By default, your app trusts any certificate that chains up to a root CA in the device's trust store. There are hundreds of CAs. An attacker who can add a root cert to the trust store — through a corporate MDM, a jailbreak tool, or instrumentation like Frida — can issue themselves a certificate for your domain and intercept traffic.

Pinning replaces "trust any CA-chained cert for this domain" with "trust only these specific certs (or these public keys)." The interception fails because the attacker's cert doesn't match.

What pinning doesn't protect against:

Pinning is one defense among many. It's not magic.

When to actually pin

The threat model question: does your app face attackers who can install custom root certificates on victim devices?

Cases where the answer is genuinely yes:

Cases where the answer is usually no:

Certificate pinning vs public key pinning

Two flavors. Different operational properties.

TypeWhat you pinRotation behavior
Certificate pinningThe full X.509 certificateApp breaks the day the cert is replaced. Must ship app update before rotation.
Public key pinningThe hash of the public key (SubjectPublicKeyInfo)App keeps working as long as the new cert uses the same key. Reuse the key across rotations.

Public key pinning is what production deployments actually use. Certificate pinning is what tutorials usually show. The difference matters enormously the first time you rotate certificates without an app update lined up.

Approach 1: Native config (recommended)

The platform-native pinning options are the most robust. They're verified by the OS's own TLS stack — not by your code, not by a third-party library that might have its own bugs.

iOS — App Transport Security with pinning:

In your Info.plist, configure NSAppTransportSecurity with NSPinnedDomains. The OS handles verification at the network layer; your code calls fetch as normal.

Android — Network Security Config:

In res/xml/network_security_config.xml, configure <pin-set> entries with public key hashes. Reference the config from AndroidManifest.xml. The OS handles verification.

What this approach gets right:

Drawbacks: configuration is platform-specific (you maintain two configs), and Android Network Security Config has some quirks around debug builds and proxy use.

Approach 2: TrustKit (iOS)

TrustKit is an Objective-C library that adds richer pinning features on top of iOS's networking — backup pins, violation reporting, fine-grained control over which domains are pinned, and graceful fallback during pin failures.

Where TrustKit helps over native config:

Where it doesn't help:

Worth it for security-sensitive apps that want observability. Overkill for most apps.

Approach 3: react-native-ssl-pinning

A community-maintained React Native library that ships its own pinning-aware fetch. Works on both platforms with a single API.

The structural problem: it provides its own fetch implementation. Your app's other HTTP code paths — Axios, image loading, WebView traffic, library-internal network calls — don't go through it. They use the standard networking stack and aren't pinned.

That's usually not what you want. The whole point of pinning is to protect against interception. If half your network traffic isn't pinned, the protection is partial.

The library also has the usual third-party-React-Native-library risks: maintenance state varies, peer ranges may not match current React Native, New Architecture support has been inconsistent.

Use this approach only if:

Approach 4: Custom native module

You write your own native pinning implementation. URLSession delegate on iOS, OkHttp CertificatePinner on Android. You expose it through a React Native module.

This is the heaviest option. Worth it when:

For everyone else, this is over-engineering. The native config approach is usually better.

Pin rotation strategy

The hardest part of pinning isn't shipping the initial pins. It's rotating without taking the app down.

The pattern that works:

  1. Pin the public key, not the certificate. If you reuse the key across rotations, most rotations don't require an app update.
  2. Always ship at least one backup pin. Two pins in the app. The active pin matches the current cert. The backup pin matches a future cert (or key) you've generated but haven't deployed.
  3. Plan rotation in two steps. First, ship an app update adding a new backup pin. Wait for adoption — at least 90% of installs on the new version. Then rotate the server cert to one matching the backup pin (now active). Then ship another app update adding the next backup pin and dropping the old one.
  4. Monitor pin failures. Whether you use TrustKit's reporting or roll your own, know when pin checks fail. Failures should be near-zero. Spikes mean either an attack or a rotation problem.

Failure modes

The ones we see most:

Every one of these is preventable with a careful operational plan. The actual TLS code is the easy part.

Doing a security audit on a React Native app?

Pinning is one item on a longer list. Our security audit covers the full surface — dependency CVEs, secure storage misconfiguration, network configuration, and the React Native specific items that don't appear in generic mobile audits.

Frequently Asked Questions

What is SSL pinning in mobile apps?

SSL pinning (more accurately TLS pinning, since SSL itself is deprecated) is the practice of restricting which TLS certificates or public keys your app will trust when connecting to a specific server. Instead of trusting any certificate that chains to a root CA in the device trust store, you trust only the specific certificate or public key you embedded in the app. It blocks an attacker who can install a custom root CA on the device — common in corporate MITM proxies, jailbreak tools, and instrumentation frameworks.

Does my React Native app need SSL pinning?

Probably not. Most consumer apps don't need it — the threat model (network attackers with custom root certs) doesn't justify the operational risk (bricking the app when certs rotate). The apps that should pin are banking, healthcare, regulated payments, and apps with explicit compliance requirements that name pinning. If your security audit doesn't explicitly require pinning, the cost-benefit usually doesn't favor it.

What's the difference between certificate pinning and public key pinning?

Certificate pinning embeds the entire X.509 certificate. When the cert rotates, the app stops working until you ship an update. Public key pinning embeds only the public key hash, which can stay constant across multiple certificate rotations as long as the same key is reused. Public key pinning is more operationally forgiving, which is why production deployments almost always use it. Cert pinning is more common in tutorials but worse in practice.

How do I implement SSL pinning in React Native?

Four approaches. Native config (iOS App Transport Security pinning, Android Network Security Config) is the most robust and least React-Native-specific — Apple and Google handle the verification natively. TrustKit is an iOS-specific library that adds backup-pin and reporting features. react-native-ssl-pinning is a community library that ships with its own fetch implementation. Custom native modules are the heavyweight option for teams with specific requirements. Most teams that need pinning should start with native config.

What happens when an SSL-pinned app's certificate rotates?

Without backup pins, every installed copy of the app stops working immediately. Users see opaque connection errors. Support gets overwhelmed. You ship an emergency app update — but App Store review takes hours to days, during which the app is broken for everyone. With backup pins, the second pin matches the new certificate (or its key), and the app keeps working. The backup-pin strategy is the difference between SSL pinning being a real security control and being a self-imposed denial-of-service.

What is a backup pin?

A backup pin is a second (or third) certificate or public-key hash you embed in the app alongside the primary pin. The TLS handshake succeeds if the server's cert matches any of the embedded pins. You rotate the server's cert to one matching a backup pin, then ship an app update adding a new backup pin and removing the now-active one. Without this strategy, certificate rotation is high-risk; with it, rotation is routine.