Why Hardcoding Certificate Pins Breaks Mobile Apps

Certificate pinning has historically been the gold standard for preventing Man-in-the-Middle (MitM) attacks in mobile applications. By explicitly defining which certificates or public keys an app shou...

Tim Henrich
September 08, 2026
5 min read
33 views

Why Hardcoding Certificate Pins Breaks Mobile Apps

Certificate pinning has historically been the gold standard for preventing Man-in-the-Middle (MitM) attacks in mobile applications. By explicitly defining which certificates or public keys an app should trust, developers could ensure their software only communicated with legitimate servers, effectively neutralizing compromised device trust stores or rogue Certificate Authorities (CAs). The compromise of the DigiNotar CA, which allowed attackers to issue fraudulent certificates for major domains, cemented pinning as a mandatory security control for high-risk applications.

However, the operational landscape has fundamentally shifted. Major platform vendors like Apple and Google are now actively discouraging static, hardcoded pinning. The reason is simple but devastating: "app bricking." When a pinned certificate expires or is rotated unexpectedly, the application permanently loses its ability to communicate with the backend until the user downloads an update from the App Store or Google Play.

Today, strict static pinning is widely considered a legacy anti-pattern. Modern mobile architectures rely on dynamic pinning, Certificate Transparency (CT) enforcement, and Runtime Application Self-Protection (RASP) to achieve Zero Trust API security without the operational landmines.

The Case Study: The "Bricked" FinTech App

To understand the danger of static pinning, we can look at an incident involving a major European challenger bank in 2023.

To comply with Payment Services Directive 2 (PSD2) requirements for secure communication, the bank's security team mandated certificate pinning. The mobile development team implemented this by hardcoding the cryptographic hash of the backend API's leaf certificate directly into the app binary.

The backend infrastructure was hosted on AWS, utilizing API Gateway and AWS Certificate Manager (ACM). ACM automatically rotates managed certificates prior to expiration to prevent outages. Thirty days before the API certificate was due to expire, AWS automatically provisioned and deployed a newly generated leaf certificate.

Because the mobile app was hardcoded to trust only the exact cryptographic hash of the old leaf certificate, it instantly rejected the new, perfectly valid certificate. Millions of users were immediately locked out of their banking app.

The remediation required an emergency code change, an expedited review process through Apple and Google, and a forced update campaign. Even then, users who had disabled automatic updates remained locked out for weeks.

The Lesson: Never pin a cloud-managed leaf certificate. If you must pin, pin the Subject Public Key Info (SPKI) of the intermediate CA, and always implement a backup pin.

Public Key (SPKI) vs. Certificate Pinning

When implementing pinning, developers must choose exactly what cryptographic element to pin. Pinning the entire X.509 certificate binary is dangerous because any change to the certificate—even a routine renewal that keeps the same underlying keys—will alter the certificate's hash and break the pin.

The modern standard, as recommended by the OWASP Mobile Application Security Verification Standard (MASVS), is to pin the Subject Public Key Info (SPKI).

The SPKI is the portion of the certificate that contains the actual public key. If your infrastructure team generates a Certificate Signing Request (CSR) to renew a certificate using the existing private key, the resulting new certificate will have the exact same SPKI hash. The app will continue to function without requiring an update.

Furthermore, OWASP MASVS-NETWORK-2 guidelines recommend pinning the Intermediate CA or Root CA rather than the leaf certificate. Pinning the intermediate CA provides a balance between security and operational flexibility. If the leaf certificate changes unexpectedly (as in the AWS incident), the app will not break, provided the new certificate is issued by the same intermediate CA.

Implementing Modern OS-Level Pinning

Historically, developers relied on third-party networking libraries to handle pinning logic. Today, the best practice is to use native, OS-level configurations. This reduces overhead, minimizes third-party dependencies, and leverages the operating system's optimized network stack.

Android: Network Security Configuration (NSC)

Since Android 7.0, pinning is handled declaratively via the network_security_config.xml file. This approach allows developers to define pins, set expiration dates, and specify backup keys without writing custom Java or Kotlin code.

Here is a production-ready example of an Android NSC implementation:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <!-- Only apply pinning to critical domains -->
        <domain includeSubdomains="true">api.yourcompany.com</domain>

        <!-- Fail-open expiration date to prevent app bricking -->
        <pin-set expiration="2025-12-31">
            <!-- Primary Pin: SPKI hash of the current Intermediate CA -->
            <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>

            <!-- Backup Pin: SPKI hash of an offline, securely stored key -->
            <pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
        </pin-set>
    </domain-config>
</network-security-config>

Notice two critical safeguards in this configuration:
1. The Backup Pin: You must always include a hash for a key you control but are not currently using. If your primary CA is compromised or you need to migrate infrastructure, you can transition to the backup key without pushing an app update.
2. The Expiration Attribute: The expiration tag ensures that if the development team forgets to update the pins in a future release, the app will "fail open" (revert to standard OS trust store validation) rather than bricking entirely.

iOS: App Transport Security (ATS)

Apple introduced declarative pinning in iOS 14 through App Transport Security (ATS). Similar to Android, this is managed via the app's Info.plist file using the NSPinnedDomains dictionary.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSPinnedDomains</key>
    <dict>
        <key>api.yourcompany.com</key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSPinnedLeafIdentities</key>
            <array>
                <dict>
                    <key>SPKI-SHA256-BASE64</key>
                    <string>7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</string>
                </dict>
                <dict>
                    <key>SPKI-SHA256-BASE64</key>
                    <string>fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</string>
                </dict>
            </array>
        </dict>
    </dict>
</dict>

For teams requiring programmatic control or supporting older iOS versions, developers can implement the URLSessionDelegate method urlSession(_:didReceive:completionHandler:) to manually validate the server's trust object against bundled public keys.

Cross-Platform Challenges (Flutter and React Native)

Cross-platform frameworks often bypass the native OS network layers, which means network_security_config.xml and Info.plist configurations may be ignored by the app's HTTP clients.

  • Flutter: By default, Flutter uses its own BoringSSL-based network stack. Developers must use the SecurityContext class to explicitly set trusted certificates.
  • React Native: React Native generally relies on OkHttp (Android) and URLSession (iOS). Developers must use native modules, such as react-native-ssl-pinning, to interface with the underlying OS network stacks and enforce pinning.

The Red Team Reality: Bypassing Pins at Runtime

While certificate pinning successfully stops network-level interception (like a rogue Wi-Fi hotspot), it is entirely ineffective against a determined attacker with physical control of the device.

The proliferation of dynamic instrumentation frameworks like Frida and mobile exploration toolkits like Objection has made bypassing static pinning trivial. An attacker or security researcher can simply connect a jailbroken or rooted device to their computer, launch Objection, and execute a single command:

objection -g com.yourcompany.app explore -s "android sslpinning disable"

This command hooks into the

Share This Insight

Related Posts

Decoding PEM, DER, and PKCS#12 Certificate Formats

The foundational formats of X.509 digital certificates have existed for decades, but the context in which infrastructure teams use them is shifting rapidly. With Google pushing for 90-day maximum cert...

Sep 09, 2026