Certificate pinning makes a client refuse any TLS certificate except the ones it expects, which blocks interception through a rogue or injected certificate authority but turns every certificate change into a potential outage. Pinning is defined here as associating a host with an expected certificate or public key, so that a valid chain to a trusted root is not enough on its own. This guide explains what to pin, when pinning is worth its operational cost, how Android, iOS and common libraries implement it, and how to rotate pins without bricking an app. It is written for mobile and API developers, application security engineers and the PKI teams who own the server certificates. Wider mobile app controls are covered in the Mobile App Security Guide.
Key takeaways
- Default to not pinning. The OWASP Pinning Cheat Sheet and Apple both say pinning is rarely needed; it suits native apps where you control both the client and the server and can update the pin set securely.
- Pin public keys, not certificates. Pin the SHA-256 hash of the SubjectPublicKeyInfo (SPKI), which survives certificate renewal when the key is kept, and is the format Android, iOS and HPKP all use.
- Always ship a backup pin. Include at least one pin for a key not yet in service, or an intermediate CA key, so a forced key change or CA migration does not take the app offline.
- Shorter certificate lifetimes raise the stakes. Public TLS certificate validity is being cut to 47 days by 2029, so leaf certificate pinning without key reuse means very frequent pin updates.
- Pinning is not anti-tampering. Anyone controlling the device can repackage the app and remove pins. Pinning protects users on hostile networks; it does not stop a determined analyst of your API.
What pinning protects against, and what it does not
Standard TLS validation accepts any certificate that chains to one of the hundreds of roots in the device trust store and matches the hostname. The OWASP Pinning Cheat Sheet names the two attacks that pinning addresses: an attacker obtaining a rogue certificate for your domain from a trusted CA, and an attacker injecting a malicious CA into the client's trust store. MITRE ATT&CK tracks the second technique as T1553.004 Install Root Certificate, and interception generally as T1557 Adversary-in-the-Middle (T1638 on mobile).
| Threat | Does pinning help? | Better or complementary control |
|---|---|---|
| Mis-issued certificate from a public CA | Yes, if the attacker's key is not in the pin set | Certificate Transparency monitoring, CAA records |
| Malicious or corporate CA added to the device trust store | Yes for apps; on Android 7.0+ user-added CAs are not trusted by apps by default anyway | Platform defaults, mobile device management |
| Public Wi-Fi interception without a trusted certificate | No extra benefit: normal TLS validation already fails | Correct TLS validation, no custom trust managers |
| Attacker with root or jailbreak on their own device | No: pins can be removed by repackaging | App attestation, server-side API controls |
| Compromised server or stolen server private key | No: the stolen key is the pinned key | Key protection in HSM or KMS, revocation, rotation |
| Browser users | Not available: browser HPKP is obsolete | Certificate Transparency, HSTS |
Malware authors use the same mechanism: ATT&CK for Mobile lists T1521.003 SSL Pinning, where malicious apps pin their command-and-control certificates to frustrate analysis. That is one reason network defenders cannot rely on TLS inspection to see all mobile traffic.
Deciding whether to pin
The OWASP cheat sheet's "when do you not pin" list is a practical gate. Do not pin if you do not control both sides of the connection, if you cannot update the pin set securely, if updating it means a disruptive redeployment (unless you control forced updates, as in a corporate fleet), if the key pair cannot be predicted before it goes into service, or if the client is not a native mobile application.
| Situation | Recommendation | Reason |
|---|---|---|
| Consumer banking or payments app talking to your own API | Pin, to intermediate CA keys plus backups, with a tested rotation plan | High-value traffic, you control both ends, regulators and testers often expect MASVS-NETWORK-2 |
| Enterprise app on managed devices with forced updates | Pin if TLS inspection is not required for that traffic | Update channel is reliable; coordinate with network team |
| App calling third-party APIs or CDNs you do not run | Do not pin | The provider can change CA or keys without notice |
| Web application in browsers | Do not pin | HPKP is obsolete; use Certificate Transparency monitoring |
| Server-to-server and service mesh traffic | Use a private CA and mutual TLS instead of public-CA pinning | Trust is already restricted to your own CA; see the mTLS Guide |
| IoT devices with long service life and rare updates | Pin to a private CA you control, not a public CA | A public CA migration during the device's life would strand it |
- Small teams: without a PKI owner and a release process that can push a pin update in days, the outage risk outweighs the benefit. Rely on platform TLS defaults and Certificate Transparency monitoring.
- Large organisations: pinning works when the mobile team, the certificate owners and the CDN or load balancer team share one calendar of key and CA changes. Make the pin set an owned configuration item.
What to pin: level and format
| Pin target | Trust granted | Outage risk | OWASP and Apple view |
|---|---|---|---|
| Root CA key | Every certificate under that root, including all its intermediates | Low | OWASP: generally not recommended, it trusts too much |
| Intermediate (issuing) CA key | Any certificate issued by that CA | Medium: breaks on CA migration or intermediate change | Apple prefers pinning CA keys so new server keys need no pin update |
| Leaf (server) key | Only your servers | High: breaks whenever the server key changes | OWASP: recommended only with a backup such as an intermediate pin or alternate keys |
- Certificate vs public key: pinning a whole certificate breaks at every renewal. Pinning the public key lets a renewed certificate with the same key pass, and lets you compute a backup pin before the certificate exists.
- Format: use the base64-encoded SHA-256 of the DER-encoded SPKI. Android's Network Security Configuration currently supports only SHA-256 digests; Apple's key is SPKI-SHA256-BASE64; RFC 7469 used pin-sha256.
- Backup pins: generate a spare key pair, keep it offline, and ship its pin now. Android's documentation says to always include a backup key so that a forced key or CA change does not require an app update to restore connectivity. Apple suggests pinning more than one key, especially for server identities. RFC 7469 made a backup pin mandatory.
- Two CAs: for resilience against a CA distrust event, include pins for intermediate keys from two different CAs and keep the ability to obtain certificates from both. See the CA Compromise and Mass Certificate Replacement playbook.
Platform implementations
Platforms are listed alphabetically. Both mobile platforms offer declarative pinning, and both OWASP MASTG and the platform owners recommend it over custom validation code.
Android: Network Security Configuration
- Configuration: a
<pin-set>inside a<domain-config>with one or more<pin digest="SHA-256">values. A chain is valid only if it contains at least one pinned public key. Available from API level 24 (Android 7.0). - Expiration: the optional
expirationattribute (yyyy-MM-dd) disables pinning after that date, so an un-updated app keeps working rather than failing. Android warns that this can let attackers bypass pins after the date. Without the attribute, pins never expire. - Debug overrides: trust anchors in
<debug-overrides>skip pinning and are ignored whenandroid:debuggableis false, which keeps test proxies out of release builds. - overridePins: on a
<certificates>source,overridePins="true"makes chains from that source bypass pinning. The default is false (true inside debug-overrides). Setting it onsrc="user"in a release build silently disables pinning for anyone who installs a CA. - Scope: applies to traffic through the Android framework (HttpsURLConnection and WebView unless a custom TrustManager is used). OkHttp has its own CertificatePinner; native code and other stacks need separate pinning.
iOS and macOS: App Transport Security identity pinning
- Configuration: under
NSAppTransportSecurityin Info.plist,NSPinnedDomainsmaps each domain toNSPinnedCAIdentities(CA keys, which must appear as an intermediate or root in the chain) orNSPinnedLeafIdentities, each holdingSPKI-SHA256-BASE64values.NSIncludesSubdomainsextends a pin one level of subdomain. - Behaviour: the app refuses to connect to a pinned domain unless the requirement is met. Apple notes pinning can only tighten trust, never loosen it.
- Custom validation: MASTG advises against implementing URLSession or WKNavigationDelegate challenge handlers unless needed; if you do, check the challenge type is server trust, call
SecTrustEvaluateWithError, and cancel the challenge on failure.
Libraries
- OkHttp CertificatePinner: pins per hostname or wildcard (
*.for one level,**.for any depth). Its own documentation carries the heading "Certificate Pinning is Dangerous!" and says not to pin without the blessing of the server's TLS administrator. - Cross-platform frameworks: React Native, Flutter and Xamarin apps may use their own HTTP stacks that bypass the platform configuration. Test every stack the app uses.
Rotation without outages
Most pinning incidents are self-inflicted: a certificate team rotates a key or changes CA, and every installed app version that does not know the new key stops working until users update. Apple's advice is to plan a fallback experience and to simulate failure events in testing with additional certificates.
- Inventory pins: record every app, version range, hostname and pin value, and which key or CA each pin represents.
- Pre-stage the next key: generate the replacement key pair now and ship its pin as the backup in the current release.
- Wait for adoption: before rotating, confirm through analytics that the share of active installs carrying the new pin meets your threshold. Force-update older versions if your policy allows.
- Rotate the server: deploy a certificate on the pre-staged key. Old and new app versions both connect because both keys are pinned.
- Ship the next backup: the next app release pins the now-current key plus a fresh backup, and drops the retired key.
- Rollback path: keep the previous certificate and key available (not revoked unless compromised) so you can roll the server back if failure rates spike after rotation.
Shrinking certificate lifetimes make this cadence matter. The CA/Browser Forum schedule cut maximum public TLS certificate validity to 200 days from 15 March 2026, with 100 days from 15 March 2027 and 47 days from 15 March 2029. Leaf pinning that assumes a new key at every renewal is not sustainable at that pace; either pin CA keys or deliberately reuse server keys across renewals within a defined key lifetime. See the Certificate Expiry Outages and 47-Day TLS Certificates Guide.
Why browsers abandoned pinning
RFC 7469, Public Key Pinning Extension for HTTP (Proposed Standard, April 2015), let websites send a Public-Key-Pins header with pin-sha256 values, a required max-age and a mandatory backup pin. It was trust on first use, so it could not protect a first visit, and a mistaken or malicious header could lock users out of a site for the whole max-age. MDN now describes HPKP as an obsolete security feature; Firefox 72, for example, dropped support citing low adoption and interoperability risk, and silently ignores the headers. Certificate Transparency, which makes every publicly trusted certificate visible in public logs, replaced it as the browser-side defence against mis-issuance. See the Certificate Transparency Guide.
Where identity fits
A pinned key is a machine identity: the server's TLS key is what the app trusts, and pinning makes that trust explicit and long-lived. Treat pinned keys as high-value non-human credentials.
- Ownership: every pinned key or CA has a named owner, a lifetime and a rotation date in the certificate inventory.
- Protection: keep the current and backup private keys in an HSM or cloud KMS; a leaked pinned key cannot be fixed by issuing a new certificate on the same key.
- Automation awareness: ACME clients and managed certificate services may generate a new key at each renewal by default, which breaks leaf pins. Configure key reuse deliberately or pin at CA level. See the Machine Identity, PKI and Certificate Lifecycle Guide.
Testing, detection and measurement
- Test that pinning works: MASTG tests for MASVS-NETWORK-2 check that a connection through an interception proxy with a trusted but unpinned certificate fails. Run this in CI against release builds, not debug builds. See the Mobile App Security Testing Guide.
- Test that rotation works: before every key or CA change, connect a release build to a staging server presenting the backup key.
- Report failures: log pin validation failures in the app (hostname, app version, presented key hash) to telemetry so you see a broken rotation or an interception attempt quickly.
- Pin failure rate: pin validation failures per 10,000 sessions by app version; a spike after a server change means rollback.
- Backup coverage: percentage of active installs whose pin set contains the next planned key, which is the go or no-go figure for rotation.
- Pin set freshness: days until the earliest pinned key or Android pin-set expiration date across supported versions.
- Stack coverage: share of the app's HTTP stacks (platform, OkHttp, WebView, native, cross-platform) with pinning verified by test.
Framework mapping
| Framework | Reference | How it applies |
|---|---|---|
| OWASP MASVS | MASVS-NETWORK-2: the app performs identity pinning for all remote endpoints under the developer's control | The direct requirement; MASVS-NETWORK-1 covers secure network traffic generally |
| NIST SP 800-53 Rev. 5 | SC-8 Transmission Confidentiality and Integrity, SC-8(1) Cryptographic Protection; SC-23 Session Authenticity | Protecting data in transit and authenticating the session endpoint |
| NIST SP 800-53 Rev. 5 | SC-17 Public Key Infrastructure Certificates; SC-12 Cryptographic Key Establishment and Management | Managing the certificates and keys that pins reference |
| NIST CSF 2.0 | PR.DS-02 | Data in transit protected |
| MITRE ATT&CK | T1557, T1638 (mobile), T1553.004 | Interception techniques pinning disrupts |
Common failure patterns
- No backup pin: a single leaf pin and an unplanned key change take every installed version offline until users update.
- Pinning a provider you do not control: a CDN, cloud load balancer or SaaS API changes CA or intermediate, and the app breaks without any change on your side.
- overridePins on user CAs in release builds: intended for testing, it disables pinning for any user who installs a CA.
- Custom trust managers that accept everything: hand-written validation that returns success on error removes both pinning and normal TLS checks. OWASP and Android both warn against writing pinning from scratch.
- Only one HTTP stack pinned: the platform configuration is set but OkHttp, a WebView with a custom TrustManager, or native code makes unpinned calls.
- Forgotten expiration dates: an Android pin-set expiration passes unnoticed and pinning silently turns off for every install of that version.
Practitioner checklist
- Pinning is used only for native app connections to endpoints you control, with a documented decision.
- Pins are SHA-256 SPKI hashes at intermediate CA or leaf level, never a single root unless justified.
- Every pin set includes at least one backup key held offline, ideally plus an intermediate from a second CA.
- Declarative platform pinning is used (Network Security Configuration, NSPinnedDomains) rather than custom validation code.
- Release builds contain no overridePins on user CAs and no debug trust anchors.
- Every HTTP stack in the app is covered and tested against an interception proxy in CI.
- A pin inventory records app versions, hostnames, key owners, rotation and expiration dates.
- Key rotations follow the pre-stage, adopt, rotate, retire sequence with a rollback certificate kept available.
- Pin validation failures are reported to telemetry and alerted on by app version.
Standards and references
- OWASP: Mobile Application Security Verification Standard (MASVS-NETWORK-2)
- OWASP: Pinning Cheat Sheet
- OWASP MASTG: Certificate Pinning (Android)
- Android Developers: Network security configuration
- Apple Developer: Identity Pinning: How to configure server certificates for your app
- IETF: RFC 7469 Public Key Pinning Extension for HTTP
- NIST: SP 800-53 Rev. 5 Security and Privacy Controls
- MITRE ATT&CK: Adversary-in-the-Middle (T1557)
Related NHI Mgmt Group resources: Mobile App Security Guide · Certificate Transparency Guide · Machine Identity, PKI and Certificate Lifecycle Guide · TLS Inspection Guide · Certificate Expiry Outages and 47-Day TLS Certificates Guide