跪拜 Guibai
← All articles
Flutter · Client-side

Guessable CA Keys: Why Flutter 3.47.8 Is a Mandatory Update

By 程序员老刘 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

This is a live, exploitable flaw: with a guessable CA key, an attacker can impersonate any server to a Dart-based client that trusts the root. Upgrading to 3.47.8 and republishing is the only way to close the TLS hole, and with 2 of the 8 keys being Microsoft code-signing certs, the blast radius extends beyond HTTPS.

Summary

Indian CA eMudhra used a flawed key-generation script in its HSM in April 2025, producing a second set of weak backup keys that later got used for real CSRs. The 8 intermediate certificates revoked in October 2026 have private keys that are 3 to 8 bits long; the actual values are 4, 56, 66, 115, 155, 156, 230, and 237. An attacker enumerating 1 to 255 on a laptop can recover one of these keys in under a second and sign a certificate for any domain.

Browsers and operating systems moved to block the compromised chains: Chrome's CRLSet, Mozilla's OneCRL, Apple and Microsoft updates. Flutter's default network stack, dart:io, keeps its own BoringSSL and a bundled Mozilla root store, and it never reads those revocation lists. So a Flutter app can still finish a TLS handshake with a revoked, forged certificate. Flutter 3.47.8 adds the intermediate CAs to BoringSSL's blacklist and, on Android 14+, starts pulling system root certificates from the updatable Conscrypt APEX module, so future revocations reach apps without a full release.

Upgrading the SDK alone doesn't shrink the exposure: old app versions in the field still carry the old trust store. Teams need to decide between a forced update, a risk warning, or a normal release, and for account/payment scenarios, coordinate with the server side. The risk assessment turns on whether the app reaches multiple public services, or only a single backend with extra authentication like pinned public keys.

Takeaways
— eMudhra's 8 intermediate CA private keys are 3-8 bit numbers; values are 4, 56, 66, 115, 155, 156, 230, 237.
— The weak keys came from a wrap/unwrap error in an HSM during April 2025 key generation, producing a separate weak set that got used.
— An attacker can brute-force any of these keys by enumerating 1 to 255 and comparing public keys; a laptop does it under a second.
— Flutter's dart:io bundles BoringSSL and a Mozilla root store, and does not check CRLSet, CT logs, or OS distrust lists by default.
— Flutter 3.47.8 (Dart 3.13.7) adds a BoringSSL blacklist for these CAs and, on Android 14+, loads system roots from the Conscrypt APEX module.
— Apps with multiple public services should upgrade quickly; apps with a single backend plus additional auth can reduce risk; apps with no extra auth must upgrade.
— Upgrading the SDK only fixes future builds; production versions need forced updates or other mitigation.
— Two of the 8 certs are Microsoft code-signing certs, so the impact includes forged signed Windows programs.
Conclusions

The switch to Conscrypt APEX on Android 14+ is the structural fix: future root revocations can reach apps via Play system updates without a full release.

The risk framework separates apps by exposure surface and existing authentication, and correctly warns that tokens or signatures don't prove security without checking coverage and replay protection.

Bundling a root store in a runtime, as Flutter does, creates a divergence from system updates and leaves a window where a revoked CA is still trusted.

Concepts & terms
CRLSet
Chrome's short-lived list of revoked certificates, pushed to browsers to block compromised CAs and intermediates.
CT log
A public ledger of issued TLS certificates; browsers consult it to detect misissued or hidden certs.
HSM
A physical device that stores and manages cryptographic keys, here a FIPS 140-2 Level 3 HSM used by eMudhra.
Conscrypt APEX
An updatable system module on Android that supplies TLS; on Android 14+ Flutter now loads system roots from it.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗