Barrieron 594 bitcoins en 25 minutos porque las llaves salían del número de serie del chip, y el fabricante dice que sus modelos nuevos no están afectados
Los 500 monederos vaciados esta madrugada tenían dos cosas en común, y ninguna era el descuido de su dueño: todos guardaban más de 0,15 bitcoin y todos estaban protegidos por una sola…

Los 500 monederos vaciados esta madrugada tenían dos cosas en común, y ninguna era el descuido de su dueño: todos guardaban más de 0,15 bitcoin y todos estaban protegidos por una sola firma. Entre las 01:31 y las 01:56 UTC alguien movió 594,48 BTC, unos 38,2 millones de dólares, repartidos en 1.324 trozos y 500 transacciones que cupieron en una ventana de tres bloques. Después consolidó 562 BTC en una única dirección que sigue quieta. Muchos de esos monederos llevaban años sin moverse y las monedas abarcaban de 2021 a 2026, un rango que coincide casi exactamente con la edad del fallo que se sospecha detrás del robo.
La explicación que circula desde entonces no habla de phishing ni de un servidor comprometido, sino de una comprobación de compilación mal escrita en el firmware de Coldcard, el monedero de hardware de la canadiense Coinkite, que durante cinco años hizo que el aparato pidiera números aleatorios a una función que no generaba azar. El equipo de ingeniería de bitcoin de Block publicó su informe sin terminar las pruebas de explotabilidad, y lo dice en la primera línea: lo saca antes porque la explotación ya estaba en marcha.
Una comprobación que pregunta si la variable existe, no si está encendida
La cadena de errores es corta y se puede seguir línea por línea porque el firmware es público. La placa de producción define la constante MICROPY_HW_ENABLE_RNG con valor cero, y tiene sentido: el aparato trae su propio envoltorio para el generador aleatorio del chip STM32. El problema está en la librería libngu, que decide qué fuente de entropía usar con #ifndef, es decir, comprobando si la constante existe. Existe, y vale cero. La compilación pasa sin avisos y la librería queda enganchada a la implementación de MicroPython, que con esa constante en cero es un generador de software llamado Yasmarang.
Yasmarang arranca una sola vez, y lo hace con esto: el número de serie del microcontrolador combinado con el contador SysTick, más los registros de hora y de subsegundo del reloj interno. Ninguno de los tres es un secreto. El número de serie es metadato de fábrica, fijo de por vida, y aparece parcialmente transformado en el número de serie USB del aparato. Los contadores son estado de tiempo que un atacante puede medir en un equipo idéntico suyo. A partir de ahí no se recoge más entropía: cada salida siguiente es una transición determinista del estado.
Libngu hace además un XOR de esa salida con un segundo Yasmarang inicializado con constantes públicas escritas en el código, y el XOR de dos cosas reproducibles es reproducible. Las comprobaciones de salud que el aparato ejecuta sobre el resultado tampoco detectan nada: una rechaza que dos valores consecutivos sean iguales, algo que un generador pseudoaleatorio decente nunca hace, y otra exige que la semilla tenga más de cuatro bytes distintos. Yasmarang aprueba las dos. El dispositivo no se preguntaba si el número venía de la fuente aleatoria, se preguntaba si parecía aleatorio.
El generador de hardware estaba ahí, y el firmware dejó de llamarlo
Lo más incómodo del caso es que el generador bueno nunca se rompió. Coldcard tiene su propia implementación que lee el periférico aleatorio del STM32, falla si hay tiempo de espera y falla si se repiten muestras, y está expuesta a Python como ckcc.rng_bytes. Hasta la versión 3.2.2 la generación de semillas la usaba. Un commit del 1 de marzo de 2021 cambió dos líneas para pedir los 32 bytes a random.bytes(), que apunta a libngu, y el cambio salió en la versión 4.0.0 el 17 de marzo de 2021. El hardware siguió funcionando perfectamente cinco años, sin que nadie lo llamara.
El hashing posterior no arregla nada, y ahí es donde falla la intuición. La semilla se pasa por SHA256d y se le añade la suma de control de BIP39, así que el resultado se ve estadísticamente uniforme y pasa cualquier test de aleatoriedad. Pero una función determinista no puede aumentar el número de entradas posibles: si hay como máximo 4.294 millones de salidas del generador, hay como máximo 4.294 millones de semillas, por muy bien repartidas que estén en el espacio de 2256.
Donde el fabricante y el investigador no dicen lo mismo
Coinkite publicó su aviso preliminar el mismo día, y es explícito en el alcance: avisa a quien generó una semilla en un Mk3 con la versión 4.0.1 o posterior de que sus fondos pueden estar en riesgo, señala que el problema llega hasta la 5.0.3, la última que soportó ese modelo, y añade que "Mk4, Q y Mk5 no están afectados según nuestro análisis temprano". Block, que le compartió sus hallazgos antes de publicar, describe los modelos actuales de otra manera: el camino de respaldo sigue ahí, y la entropía que el elemento seguro inyecta al arrancar se hashea para quedarse con cuatro bytes.
Por buena que sea la calidad de las entradas originales, solo cuatro bytes del resumen llegan a la función de resiembra. Y esa función reemplaza una sola palabra de 32 bits del estado interno del generador, sin aceptar el resumen completo, sin inicializar un generador criptográfico y sin resembrar el respaldo de MicroPython.
Traducido a aritmética, para un estado de respaldo y un historial de llamadas fijos quedan como máximo 232 flujos de salida distinguidos con seguridad, con una media de unos 231 intentos. Cuatro mil doscientos noventa y cuatro millones de candidatos no es una cifra tranquilizadora en 2026, y desde luego no es 2256. Las dos afirmaciones no se contradicen del todo, porque "afectado" no significa lo mismo en boca del fabricante que del investigador, pero un titular que diga que los modelos nuevos están bien se está apoyando en la definición más estrecha de las dos.
| Aparato y firmware al generar la semilla | Si el atacante conoce los relojes | Techo si no los conoce |
|---|---|---|
| Mk1; Mk2/Mk3 hasta v3.2.2 | ≈2256 | ≈2256 |
| Mk2/Mk3 v4.0.0 a v4.1.9 | 1 candidato (determinista) | <240,7 |
| Mk4/Q/Mk5 con resiembra correcta | ≤232 (4.294.967.296) | <273,3 |
El umbral de 0,15 bitcoin dice cómo trabajó el atacante
Hay un detalle del barrido que nadie ha subrayado y que encaja con el diagnóstico técnico: todos los monederos vaciados eran de firma única y todos superaban los 0,15 BTC. Un ladrón con una lista de claves filtradas no tiene motivo para dejar el polvo sobre la mesa, porque gastar una dirección conocida no le cuesta nada. Un ladrón que está reconstruyendo semillas por fuerza bruta sí, porque cada candidato tiene un coste de derivación y validación, y por debajo de cierto saldo el cálculo no se paga. Ese umbral es exactamente la forma que tiene la economía de un ataque de enumeración, no la de una fuga.
El otro detalle es el oráculo. Para comprobar si un candidato es el correcto basta una dirección o un xpub, datos que están en la cadena. Y el problema va más allá de las semillas BIP39: la misma función alimenta las claves privadas de los monederos de papel, donde la salida se convierte directamente en clave secp256k1 sin derivación intermedia y la dirección impresa hace de oráculo, además de las máscaras del reparto Seed XOR, las claves efímeras de clonado y de cifrado USB, el material de Key Teleport y el secreto TOTP de Web2FA.
Dos vías de escape se mantienen intactas, y ambas consisten en no confiar en el generador del aparato. La primera es la frase de contraseña BIP39, que según el análisis temprano de Coinkite deja el riesgo en mínimos, y no es el PIN del dispositivo. La segunda es el camino de dados: al menos 99 tiradas de un dado de seis caras que el firmware hashea directamente sin pasar por el generador. En un aparato de seguridad de varios cientos de dólares, la fuente de entropía que sigue siendo fiable es un cubo de plástico.
La otra cara
Nada de lo anterior demuestra que este fallo sea la causa del barrido, y conviene decirlo porque la cobertura se ha bifurcado. CoinDesk lo presenta como causa directa. Cointelegraph, The Block y bitcoin.com insisten en que el vínculo no está establecido y que el aviso de Coinkite es preventivo. Block tampoco reclama una demostración: dice que no aporta ningún banco de pruebas de fuerza bruta de extremo a extremo y que el coste práctico depende del número de serie disponible, del momento del arranque y de las llamadas previas al generador.
Y hay algo que juega a favor de Coinkite en el peor día de su historia: el fallo se pudo localizar en horas, con números de commit y de línea, porque el firmware es abierto. Un aparato cerrado con el mismo defecto seguiría siendo un misterio esta mañana, y sus dueños no tendrían ni tabla de versiones afectadas ni salida de emergencia. El precio de esa transparencia es que el error estuvo cinco años a la vista de cualquiera en GitHub sin que nadie lo mirara.
En términos de mercado, 38 millones no mueven nada: el bitcoin cotizaba por encima de 64.000 dólares durante el barrido y recuperó los 65.000 después, cerrando julio con una subida superior al 10%. Pero el semestre con más incidentes de la historia llevaba 212 exploits y más de 1.000 millones robados, casi todos en contratos, puentes y plataformas. Este es de otra familia. No falló ninguna cadena ni ningún contrato, y tampoco la custodia, como en el caso de Ostium, donde el precio era falso pero la firma era buena. Falló la premisa sobre la que se construye la autocustodia: que el número que nadie puede adivinar es realmente inadivinable. Estar desconectado cinco años no protegió a nadie, porque el atacante no necesitaba llegar al aparato.
- El informe técnico formal de Coinkite, que su aviso anuncia como pendiente, y si mantiene que Mk4, Q y Mk5 no están afectados después de leer el análisis de Block.
- La validación en hardware real de los espacios de búsqueda: Block admite que el comportamiento de los relojes en arranque frío y la generalización de las mediciones entre unidades están sin medir.
- Los 562 BTC consolidados en una sola dirección quieta, y si aparecen en un mezclador, en un puente o en un exchange con identificación.
- Si el barrido continúa. Los monederos por debajo de 0,15 BTC quedaron fuera esta vez, y el coste de derivación baja cuando el atacante ya ha perfilado el dispositivo.
- Si aparecen víctimas con monederos de papel, con reparto Seed XOR o con Key Teleport, que son vías distintas a la semilla y con oráculos propios.
- Si algún esquema multifirma se ve afectado: solo queda protegido si el quórum incluye aparatos no vulnerables, y aquí las 500 víctimas eran de firma única.
- Cómo reacciona el resto del sector, porque el patrón del fallo, una comprobación de compilación que verifica existencia y no valor, no es exclusivo de este fabricante.
Si tienes un Coldcard, lo único que determina tu exposición es la versión del firmware que corría el aparato en el momento en que creaste la semilla, no cuándo lo compraste ni qué versión tienes ahora. Actualizar no repara una semilla ya generada, y exportarla a otro monedero tampoco: la semilla insegura sigue siéndolo en cualquier software que la reciba. El paso concreto de hoy es comprobar con qué versión generaste, añadir frase de contraseña si aplica y migrar sin prisa a una semilla nueva.
Basado en: informe de Block Bitcoin Engineering and Security, aviso de seguridad de Coinkite, CoinDesk, The Block, Cointelegraph, bitcoin.com, TFTC, repositorio público del firmware de Coldcard en GitHub.