Une première vague distincte du même exploit avait déjà emporté 594 BTC (~38 millions de dollars) d'environ 500 portefeuilles multi-signatures en 25 minutes vers 01:31 UTC . Galaxy Research, Chainalysis et l'équipe d'ingénierie de Block ont tous, indépendamment, lié ces vols à la même vulnérabilité Coldcard .
L'équipe d'ingénierie et de sécurité Bitcoin de Block, dirigée par l'ingénieur Clay Garrett, a identifié que l'attaquant a utilisé un compte payant chez un fournisseur bien connu de services blockchain pour identifier et interroger efficacement les adresses vulnérables . Le schéma on-chain de l'attaquant — des balayages séquentiels et inhabituellement rapides d'adresses partageant la même faiblesse — a mis la puce à l'oreille des enquêteurs. Block a confirmé des preuves matérielles reliant l'activité de l'opérateur directement à l'infrastructure de ce fournisseur .
L'enquête de Block a découvert ce que Garrett a décrit comme une « spécificité extraordinaire, jusqu'au niveau du compte » . Le service d'analyse a effectivement servi d'outil de reconnaissance, permettant à l'attaquant de cartographier rapidement quelles adresses avaient été générées sur un firmware vulnérable et de prioriser les cibles les plus riches .
Le bug a été introduit dans un commit du firmware de mars 2021 (à partir de la version 4.0.1 du firmware Mk3) lors d'une migration vers la bibliothèque libsecp256k1 de Bitcoin Core . Une erreur de macro de configuration de build a fait que le firmware a contourné le générateur matériel de nombres aléatoires (TRNG) STM32 dédié de l'appareil et est tombé en recours sur le générateur logiciel déterministe Yasmarang de MicroPython .
La configuration de la carte de production définissait MICROPY_HW_ENABLE_RNG à zéro parce que Coldcard avait son propre wrapper matériel RNG séparé. Mais la bibliothèque libngu n'a pas réussi à appeler correctement ce wrapper : sa condition de garde (#ifndef MICROPY_HW_ENABLE_RNG) testait uniquement si la macro était définie, et non si sa valeur était non nulle . Comme la macro était définie (mise à zéro), libngu a silencieusement conclu que le chemin matériel était disponible et s'est lié à la fonction logicielle rng_get() de MicroPython .
Cela a réduit l'entropie effective à environ 32–40 bits (au lieu des 128+ bits prévus), ce qui signifie qu'il n'y avait qu'environ 4 milliards de valeurs de seed possibles — trivialement cassable par force brute avec du matériel moderne . Les seeds générées sans ajout de jets de dés par l'utilisateur ou sans phrase de passe BIP 39 étaient entièrement exposées .
Le PDG de Coinkite, Rodolfo Novak (NVK), a ensuite reconnu l'erreur : « J'ai explicitement mis MICROPY_HW_ENABLE_RNG à zéro, pensant que nous n'avions besoin d'aucune des deux versions, mais ce n'est pas ce que ça fait » .
| Concernés | Non concernés |
|---|---|
| Coldcard Mk3, firmware 4.0.1 à 5.0.3 | Mk4, Q, Mk5 (selon l'analyse initiale de Coinkite) |
| Seeds générées sans jets de dés utilisateur ni phrase de passe BIP 39 | Seeds générées avec jets de dés utilisateur ou phrase de passe |
Coinkite a ensuite élargi son avis à certaines versions de firmware Mk4, Mk5 et Q après une analyse plus approfondie, et a publié des mises à jour d'urgence pour tous les modèles concernés .
Cet exploit a ébranlé l'une des promesses fondamentales de l'auto-conservation — à savoir que l'élément sécurisé d'un portefeuille matériel garantit une sécurité cryptographique quels que soient les bugs logiciels .
Pour une analyse technique détaillée, consultez le rapport d'ingénierie de Block et le document technique de Coinkite .