Security

Certificate pinning is mostly dead, but mobile apps didn't get the memo

May 28, 20268 min readCertPulse Engineering

Certificate pinning had a moment. Between 2011 and 2015, after watching a Dutch CA get fully compromised (DigiNotar) and then Symantec's slow-motion distrust by Google, it felt reasonable to bolt your trust directly to a specific certificate and stop relying on the public CA system to behave itself. Browsers shipped HTTP Public Key Pinning. Mobile apps adopted it. Banking apps treated it as mandatory.

Then HPKP died. Chrome deprecated it in 2017 and pulled it in 2018, for the same reasons it never should have shipped: a single misconfiguration could turn into a multi-month outage, and attackers could weaponize it ("RansomPKP") to lock legitimate operators out of their own domains. Browsers moved to Certificate Transparency and Expect-CT. Stop trusting one exact key. Trust the ecosystem, but make every cert publicly logged so anything weird shows up fast.

Mobile didn't get that memo. Mobile pinning is still everywhere. It's in OWASP MASVS. It shows up in pentest reports as a finding when it's missing. And with the CA/Browser Forum's SC-081v3 ballot now actively shrinking cert lifetimes (200 days as of March 2026, 100 days in March 2027, 47 days by March 2029), the math behind mobile pinning is breaking in a way that's going to bite a lot of teams.

The arithmetic stops working

A pinned leaf certificate has to be in your binary. Your binary lives in an app store. App store rollouts take time. iOS is forced-update-hostile by design. Users update on their schedule, and a meaningful chunk of your install base will be on a release that's 30, 60, or 90 days old at any given moment.

Today, with 398-day certificates, you have slack. You renew, ship the new pin in the next release, give users a few months to update, then cut over. Painful, doable.

Under a 47-day cert lifetime, the rotation cadence is faster than your slowest-updating users will reasonably move. Even at 100 days (which we hit in under a year), the gap is uncomfortable. If you pin a leaf cert and the cert rotates eight times a year, every rotation is a forced-update event for the long tail of your install base, or it's an outage for them. No third option.

This isn't hypothetical. Teams running aggressive cert rotation (Let's Encrypt's 90-day default, which a lot of internal infra already uses) have been hitting this for years. The industry just hasn't internalized that it's becoming everyone's problem.

Which thing are you actually pinning?

Engineers reach for one of three strategies, and each one fails differently when the CA does something perfectly normal.

Pin the leaf certificate. Maximum security, minimum operational sanity. Every rotation requires an app release. Under shortened lifetimes, this is dead on arrival unless you control both endpoints and can force-update your users. If your CTO ever asks "can we just push a hotfix," the answer for pinned leaf certs is "in about ten days for Android, longer for iOS, and never for the 8% of users who disabled auto-update."

Pin the intermediate certificate. The classic compromise. CAs rotate intermediates less often than leaves, so you get more time between rotations. The catch: CAs do rotate intermediates, and when they do, they often don't telegraph it as loudly as you'd like.

The Let's Encrypt R3-to-R10/R11 transition is the canonical example. R3 had been signing Let's Encrypt leaves for years. In 2024, Let's Encrypt began moving to R10 and R11, intermediates chained under their own ISRG Root X1 instead of cross-signed by IdenTrust. Plenty of mobile apps had pinned R3. Plenty of those apps broke, quietly, only on users whose certs happened to be issued by the new intermediate. The fix shipped six weeks later for the apps that noticed. Some apps never noticed at all because their telemetry didn't surface TLS handshake failures distinctly from "user is offline."

Pin the SPKI (Subject Public Key Info) of a long-lived key. This is the strategy that mostly works, but only if you actually control the key. SPKI pinning lets the certificate around the key rotate freely. You can renew the cert every 47 days, every 7 days, every day, as long as you keep using the same keypair. The pin doesn't care about the cert; it cares about the public key inside it.

The footgun: most teams pin the SPKI of an intermediate they don't control. Same problem as straight intermediate pinning. The CA can decide tomorrow that the intermediate's key is being retired, and now you're shipping an emergency release.

The version that holds up is pinning the SPKI of a key in a CSR you generated, where you control the rotation schedule. That means either a private CA issuing the cert, or pre-generating a long-lived keypair and asking your public CA to issue against it. Some CAs allow this. Not all do, and ACME doesn't always make it easy.

What a migration actually looks like

If you have a fleet of mobile clients pinning leaf certificates today, here's the path that survives shortened cert lifetimes without a flag day.

Pin a key you control, not a cert someone else controls. Generate a long-lived keypair offline. Store the private key somewhere sensible (HSM, KMS, your platform's secret manager). The choice depends on your threat model. It shouldn't be on a developer laptop. Use that same keypair for CSRs across many cert rotations. Your pin is now stable across renewal cycles, regardless of how short those cycles get.

Ship multiple pins. Always at least two: the current production key and a backup. The backup is what you cut over to if the current key is compromised or you need to rotate emergency-style. Apps that only ship one pin have set themselves up for the worst day of their on-call rotation.

Build a kill switch. A remote config flag, fetched on app start, fail-open if unreachable, that can disable pinning entirely. Yes, this weakens the security guarantee of pinning. It also means that when something goes wrong at 2am, you have an option besides "ship a hotfix to the app store and pray." Decide ahead of time what conditions warrant flipping the switch, and make sure flipping it is logged and alerts your security team. The kill switch is a fire extinguisher, not a furniture choice.

Don't do dynamic pinning. TOFU-style "pin whatever cert we see on first connection" sounds clever and is mostly a way to bake an attacker's MITM cert permanently into your client. The first connection is the connection an attacker most wants to intercept. If you genuinely don't know what to pin at build time, you probably shouldn't be pinning.

Plan the rollout. Ship the new pin alongside the old pin for at least one full release cycle, more if your slow tail is meaningful. Only after you have confidence that the bulk of your install base accepts both, retire the old one. Pinning migrations run concurrently for months. They aren't flag-day cutovers.

You can't fix what you can't see

The deepest problem with mobile pinning isn't the technique. It's that most organizations have no idea what their mobile clients are actually pinning.

Pinning configurations live in app source, in network_security_config.xml on Android, in OkHttp CertificatePinner instances, in URLSessionDelegate overrides on iOS, in third-party SDKs that ship their own pinning policy. Different teams ship different apps with different pin sets and different rotation assumptions. Five years of acquisitions later, nobody knows what any of it does.

The first step in any pinning migration is an inventory. Audit every mobile codebase. Find every place pinning is configured. Document what is pinned (leaf, intermediate, SPKI), what key it ultimately references, who owns rotating it, and what the kill-switch story is. Unglamorous, and the only way to avoid surprise outages.

On the server side, the parallel question is "what cert is about to replace the one our apps are pinning?" Certificate Transparency monitoring catches this. Every cert issued for your domains lands in CT logs in near-real-time. If your CA is about to rotate the intermediate, or a new cert with a different key is about to go live, CT logs see it before your users do. Wire CT log monitoring into your alerting and you turn a future outage into a Tuesday afternoon ticket.

This is the visibility gap CertPulse fills on the server side: multi-cloud certificate inventory across ACM, Key Vault, and Certificate Manager, plus CT log monitoring for your domains, so when a new cert appears for an endpoint your mobile clients pin to, you find out from a notification rather than a support ticket. It doesn't solve the mobile-side problem of inventorying what your apps pin. It does solve the server-side problem of knowing what's about to change underneath them.

The honest take

Mobile pinning isn't dead. Compliance frameworks reference it. Security teams expect it. There are still real threats it mitigates that CT-only models don't, like a compromised CA issuing a valid-looking cert for your domain with logs you somehow miss.

But the form of pinning most apps actually ship (leaf certs hardcoded in binaries, no kill switch, no SPKI of a controlled key, no real plan for the next CA intermediate rotation) was already creaky in the 398-day era. At 47 days, it's a liability waiting for the wrong week to surface.

The migration is straightforward and you don't have to do it all at once. Pick one app, generate a long-lived keypair, ship backup pins, build the kill switch, get CT log monitoring on the relevant domains. Repeat per app. By the time the 100-day phase lands in March 2027, cert rotation is a non-event, not a release-cycle scramble.

The teams that wait will find out, the hard way, what 2am app store reviews feel like.

This is why we built CertPulse

CertPulse connects to your AWS, Azure, and GCP accounts, enumerates every certificate, monitors your external endpoints, and watches Certificate Transparency logs. One dashboard for every cert. Alerts when auto-renewal fails. Alerts when certs approach expiry. Alerts when someone issues a cert for your domain that you didn't request.

If you're looking for complete certificate visibility without maintaining scripts, we can get you there in about 5 minutes.

Certificate pinning is mostly dead, but mobile apps didn't get the memo | CertPulse