Cuando Falla la Matemática: Dentro de la Vulnerabilidad de Entropía de COLDCARD
Análisis técnico del bug de RNG que presuntamente debilitó la autocustodia de Bitcoin — y por qué la autocustodia sigue siendo innegociable
Contenido
- Qué Pasó
- Yasmarang: Cuando un PRNG de Juguete Reemplaza a un TRNG de Hardware
- El Bug de
#ifndefvs#if - Espacio de Búsqueda: ¿Cuántos Candidatos?
- IA como Arma de Doble Filo
- El Hotfix que Brickea: Un Nuevo Bug en el Fix
- Cómo Verificar si Tu Seed Está Afectada
- La Lección Mayor: La Autocustodia Sigue Siendo Imperativa
- Referencias
Qué Pasó
El 30 de julio de 2026, Coinkite publicó un aviso de seguridad advirtiendo que un bug en el firmware de COLDCARD había debilitado la entropía de las frases semilla generadas en dispositivos afectados. El equipo de Ingeniería y Seguridad de Bitcoin de Block publicó simultáneamente un análisis técnico identificando la causa raíz.
El informe de Block incluye una declaración contundente: “active exploitation is under way” (explotación activa en curso). Usuarios han perdido Bitcoin. Esto no es teórico.
La causa raíz: un bug sutil en una directiva del preprocesador hizo que la generación de semillas de wallet usara un PRNG de software no criptográfico llamado Yasmarang en lugar del generador de números aleatorios verdadero (TRNG) de hardware STM32 que COLDCARD estaba diseñado para usar.
La Analogía
Imagina que la llave de tu casa no se corta de una llave en blanco aleatoria, sino que se genera a partir de dos datos: el número de serie impreso en el cerrojo de tu puerta (visible para cualquiera que se acerque) y el milisegundo exacto en que giraste la llave por primera vez.
En el bug de COLDCARD, el “número de serie del cerrojo” es el UID del chip — un identificador de fábrica grabado en cada microcontrolador STM32 al fabricarlo. Es fijo de por vida, legible desde la memoria, y parcialmente transformado en el número de serie USB del COLDCARD. El “milisegundo en que giraste la llave” es el contador SysTick — un timer de hardware que cuenta hacia atrás desde un valor fijo en cada ciclo de reloj y se reinicia cada milisegundo. En el momento en que Yasmarang se inicializa, captura el valor actual de SysTick y le aplica XOR con el UID.
Si alguien conoce ambos valores — o puede acotarlos a un rango suficientemente pequeño — puede fabricar una llave idéntica. No necesita romper ningún cifrado. Solo necesita repetir la misma aritmética que el dispositivo ejecutó. Eso es lo que pasó aquí, pero para llaves privadas de Bitcoin.
Yasmarang: Cuando un PRNG de Juguete Reemplaza a un TRNG de Hardware
El código fuente muestra que MicroPython incluye un PRNG de software como fallback para MCUs sin RNG de hardware. Se llama Yasmarang, y nunca fue diseñado para uso criptográfico.
El Algoritmo
El estado interno de Yasmarang son solo cuatro variables: pad (32 bits), n (32 bits), d (32 bits), y dat (8 bits). Se inicializa una sola vez:
pad = *(uint32_t*)MP_HAL_UNIQUE_ID_ADDRESS ^ SysTick->VAL; // UID del chip XOR timer n = RTC->TR; // registro de tiempo del RTC d = RTC->SSR; // subsegundos del RTC dat = 0; // Cada llamada posterior: pad += dat + d * n; pad = (pad << 3) + (pad >> 29); // rotación de 3 bits n = pad | 2; d ^= (pad << 31) + (pad >> 1); dat ^= (char)pad ^ (d >> 8) ^ 1; return pad ^ (d << 5) ^ (pad >> 18) ^ (dat << 1); // 32 bits de salida
Por Qué Es Catastrófico
1. Estado minúsculo y no criptográfico. El estado inicial proviene del UID del chip (un identificador de fábrica, no un secreto), el contador SysTick (~80,000 valores posibles en Mk2/Mk3), y los registros del RTC (correlacionados con la hora de arranque, potencialmente estáticos en cold boot). Eso no es entropía — es metadata del dispositivo y timing.
2. Sin reseed. Después de la inicialización, nunca se mezcla nueva entropía. Cada salida es una función determinística del estado inicial. Conoces el estado → reproduces el stream completo.
3. Operaciones no criptográficas. Shifts, XORs y sumas simples no son un cifrado. Un CSPRNG como HMAC-DRBG resistiría la predicción incluso con conocimiento parcial del estado. Yasmarang no ofrece esa garantía.
4. El SHA256d al final no ayuda. La generación actual de wallets hashea los 32 bytes de salida del RNG con SHA256d. Pero el hash determinístico no puede aumentar el número de entradas posibles. Si hay solo 232 salidas posibles del RNG, hay como máximo 232 semillas posibles, independientemente del hash.
| Propiedad | CSPRNG (ej. HMAC-DRBG) | Yasmarang |
|---|---|---|
| Estado interno | 256+ bits | ~104 bits (no aleatorios) |
| Fuente de entropía | TRNG de hardware, reseed periódico | UID + timer, una vez |
| Resistencia a predicción | Computacionalmente inviable | Trivial si se conoce el estado |
| Reseeding | Periódico desde TRNG | Nunca (o 32 bits en Mk4) |
| Estándar | NIST SP 800-90A | Ninguno |
El Bug de #ifndef vs #if
La regresión entró en marzo de 2021, cuando COLDCARD migró sus operaciones de curva elíptica a libsecp256k1 de Bitcoin Core. La generación de semillas de wallet pasó de ckcc.rng_bytes() (que usaba el TRNG de hardware) a ngu.random.bytes() (que resolvió a Yasmarang).
El Bug del Preprocesador
El código de libngu verificaba la disponibilidad del RNG de hardware con:
#ifndef MICROPY_HW_ENABLE_RNG #error "get a HW TRNG plz" #endif
#ifndef verifica si el macro está definido — no si su valor es nonzero. La configuración de board de COLDCARD lo definía como:
#define MICROPY_HW_ENABLE_RNG (0)
El macro está definido — su valor es 0. #ifndef lo ve como “definido” y no dispara el #error. La compilación continúa. Pero como el valor es cero, MicroPython compila su fallback Yasmarang en lugar del RNG de hardware.
La Verificación Correcta
#if !MICROPY_HW_ENABLE_RNG #error "get a HW TRNG plz" #endif
#if evalúa el valor. Si es 0, !0 es verdadero, y el #error se dispara. La compilación falla. El desarrollador se da cuenta.
Por Qué Este Patrón Es Peligroso Más Allá de COLDCARD
Este no es un error exclusivo de Coinkite. Es un patrón que afecta a cualquier codebase C/C++ que mezcla verificaciones #ifdef con definiciones de macros numéricos:
| Definición del macro | #ifdef / #ifndef |
#if |
¿Detecta valor 0? |
|---|---|---|---|
#define FOO |
definido | #if FOO → 0 (falso) |
N/A |
#define FOO 1 |
definido | #if FOO → 1 (verdadero) |
Sí |
#define FOO 0 |
definido | #if FOO → 0 (falso) |
#ifndef falla aquí |
En C embebido, es común definir features como 0 o 1 en lugar de definido/no-definido. Si una librería verifica con #ifdef mientras la config de board define como 0, el guard pasa silenciosamente.
Lecciones para Revisión de Código
- Nunca mezcles
#ifdefcon valores numéricos. Si defines como0/1, usa siempre#if. Si quieres verificar existencia, usa#ifdef. - Establece una convención por proyecto. O todo es booleano (
#define FOO 0/1, verifica con#if FOO) o existencial (#define FOOo nada, verifica con#ifdef FOO). - Agrega verificación de símbolos en build-time. El fix de COLDCARD ahora excluye explícitamente el objeto fallback de MicroPython y agrega un check que falla la compilación si
rng_get()no viene del board. - Verifica reachability end-to-end, no solo presencia. El código del TRNG estaba en el binario — simplemente no se llamaba desde el path de generación de semillas. La revisión existente confirmó que el código estaba ahí, pero nunca verificó qué implementación de
rng_get()el call path realmente alcanzaba.
Este bug pertenece a una categoría más amplia que ha causado algunas de las peores vulnerabilidades de la historia:
- Heartbleed (OpenSSL, 2014): el bounds check existía en una rama que no se tomaba
- goto fail (Apple, 2014): un
gotoduplicado saltaba la validación del certificado - COLDCARD (2026): el TRNG estaba en el binario pero la resolución de símbolos tomaba el fallback
La lección común: la presencia de código seguro en el binario no prueba que el runtime lo use. La verificación debe ser reachability end-to-end, no solo presencia.
Espacio de Búsqueda: ¿Cuántos Candidatos?
El análisis de Block proporciona estimaciones detalladas de espacio de búsqueda para cada dispositivo afectado:
Mk2/Mk3 v4.0.0–4.1.9
Estos dispositivos no tienen reseed criptográfico. Si el atacante conoce el UID del dispositivo, estado de timers e historial de llamadas RNG:
- Timers conocidos: 20 candidatos — determinístico. La semilla se puede reproducir exactamente.
- SysTick desconocido (UID conocido): ~80,000 valores ≈ 216.3
UID_low32 XOR SysTickcompletamente desconocido: como máximo 232- Límite superior amplio (todos los timers independientes): ~240.7
¿Cómo Podría un Atacante Obtener el UID, el Estado de Timers y el Historial de Llamadas?
Ninguno de estos valores es un secreto criptográfico. Pueden obtenerse o acotarse a través de varios canales realistas:
- UID del dispositivo (32 bits bajos): El UID del STM32 es un identificador de fábrica, no un secreto. Es legible desde la memoria del chip y se transforma parcialmente en el número de serie USB del COLDCARD. Si el atacante tuvo acceso físico al dispositivo — aunque sea brevemente — o si la víctima publicó una foto del dispositivo mostrando el número de serie, o si el número fue registrado por un host USB comprometido, los 32 bits bajos del UID pueden ser recuperables. Incluso sin el valor exacto, el atacante puede acotarlo a un rango pequeño basándose en el lote de fabricación del dispositivo.
- Valor de SysTick: SysTick es un contador periódico que se reinicia cada milisegundo. En Mk2/Mk3 tiene ~80,000 valores posibles. Pero el atacante no necesita probar los 80,000 — puede perfilar la secuencia de boot en su propio dispositivo idéntico. El boot del firmware toma un número aproximadamente predecible de ciclos de reloj antes de la primera llamada al RNG. Midiendo esto en un Coldcard propio del mismo modelo, puede acotar la ventana de SysTick a un rango mucho menor. Si el RTC de la víctima era estático o cero durante cold boot (lo que el análisis de Block sugiere probable en Mk2/Mk3), SysTick se convierte en la variable principal, y 80,000 candidatos es una búsqueda trivial.
- Historial de llamadas RNG: El número de veces que se llamó
rng_get()antes de la generación de la semilla determina la posición en el stream de Yasmarang. En la práctica, la secuencia de boot es determinística — el mismo firmware ejecuta los mismos pasos de inicialización en el mismo orden. El atacante puede reproducir esto en su propio dispositivo y determinar el conteo exacto de llamadas antes de la generación del seed. Si la víctima realizó operaciones adicionales que consumen RNG (generar un paper wallet, tiradas de dados que aún llamaron al PRNG, etc.), el atacante puede necesitar enumerar algunos offsets plausibles, pero esto multiplica el espacio de búsqueda por una constante pequeña, no por un factor exponencial.
La clave: ninguno de estos valores es un secreto. Son metadata del dispositivo e información de timing. El atacante no necesita romper ningún cifrado — solo necesita repetir la misma aritmética que el dispositivo ejecutó en el boot.
Mk4/Q/Mk5
Estos dispositivos añaden un reseed del secure element en el boot, pero solo 32 bits de entropía llegan al estado del PRNG:
- Estado fallback conocido + historial de llamadas: como máximo 232 streams de salida distinguibles
- Enumeración promedio: ~231 candidatos
- Límite superior amplio (timers independientes + reseed): ~273.3
Cómo una Dirección Pública se Convierte en un Oráculo de Validación
El ataque no requiere acceso al dispositivo de la víctima ni a sus llaves privadas. Solo requiere una pieza de información pública: cualquier dirección Bitcoin que se sepa pertenece al wallet de la víctima.
La razón: cada dirección Bitcoin se deriva de una llave pública, que se deriva de la semilla a través de paths de derivación BIP-32. Dada una semilla candidata, el atacante puede derivar determinísticamente la misma secuencia de direcciones que el wallet produciría. Si alguna dirección derivada coincide con una dirección conocida de la víctima, la semilla candidata es correcta.
¿De dónde vienen estas direcciones conocidas?
- Transacciones on-chain: Cada transacción Bitcoin es pública. Si la víctima alguna vez recibió o envió Bitcoin, sus direcciones son permanentemente visibles en la blockchain. Un atacante monitoreando la blockchain puede recolectar direcciones asociadas a un xpub específico.
- Direcciones de depósito en exchanges: Si la víctima envió Bitcoin desde su COLDCARD a un exchange, la dirección de envío está on-chain y es rastreable.
Una vez que el atacante tiene una sola dirección conocida, el ataque es cómputo puro: generar semilla candidata → derivar path BIP-32 → derivar dirección → comparar. Repetir 232 veces para Mk4/Q/Mk5, o tan solo 80,000 veces para Mk2/Mk3 con timers conocidos. El oráculo nunca toca el dispositivo de la víctima.
Tabla Resumen
| Dispositivo / Firmware | Atacante conoce timers | Límite con timers ocultos |
|---|---|---|
| Mk1; Mk2/Mk3 hasta v3.2.2 | ~2256 | ~2256 |
| Mk2/Mk3 v4.0.0–4.1.9 | 20 | <240.7 |
| Mk4/Q/Mk5 (reseed exitoso) | ≤232 | <273.3 |
| Mk4/Q/Mk5 (sin reseed)* | 20 | <241.3 |
* Path condicional; la falla ordinaria de secure element en producción parece detenerse en lugar de continuar.
Dispositivos Afectados — Tabla Completa
| Dispositivo | Firmware al generar semilla | Estado |
|---|---|---|
| Mk1 | Todos hasta v3.0.6 | No afectado (fuera de la regresión) |
| Mk2 | Hasta v3.2.2 | No afectado (usa TRNG de hardware) |
| Mk2 | v4.0.0–4.1.9 | Afectado — sin reseed seguro |
| Mk3 | Hasta v3.2.2 | No afectado (usa TRNG de hardware) |
| Mk3 | v4.0.0–4.1.9 | Afectado — sin reseed seguro |
| Mk4 | Producción v5.0.0 en adelante (antes de 5.6.0) | Afectado — reseed de 32 bits |
| Q | Toda la producción (antes de 1.5.0Q) | Afectado — reseed de 32 bits |
| Mk5 | Toda la producción (antes de 5.6.0) | Afectado — reseed de 32 bits |
| TAPSIGNER / OPENDIME / SATSCARD | Todos | No afectado (codebase diferente) |
Versiones de Firmware Corregidas
| Modelo | Firmware corregido |
|---|---|
| Mk3 | 4.2.0 o posterior |
| Mk4/Mk5 (Standard) | 5.6.0 o posterior |
| Mk4/Mk5 (Edge) | 6.6.0X o posterior |
| Q (Standard) | 1.5.0Q o posterior |
| Q (Edge) | 6.6.0QX o posterior |
Timeline Técnico
- 28 de enero, 2021: El guard vulnerable de libngu para STM32 existe.
- 1 de marzo, 2021: COLDCARD migra la generación de wallets a libngu.
- 17 de marzo, 2021: Firmware v4.0.0 incluye el path vulnerable.
- 11 de marzo, 2022: Se agrega la API de reseed de 32 bits y el reseed de boot del Mk4.
- 14 de marzo, 2022: Primer Mk4 de producción v5.0.0 incluye el reseed.
- 30 de julio, 2026: Block y otros investigadores notan reportes de usuarios perdiendo fondos. Se encuentra la causa raíz.
- 31 de julio, 2026: Firmware corregido disponible para todos los modelos afectados.
- 3 de agosto, 2026: La comunidad reporta que el hotfix introduce un bug de recuperación del TRNG que puede brickear dispositivos. PR #692 y #693 propuestos.
IA como Arma de Doble Filo
El firmware de Coinkite siempre ha sido de código abierto. El análisis de Block asume que alguien usó IA para revisar el código público del firmware y descubrió el bug antes que Coinkite.
El detalle más revelador: Coinkite también usó uno de los mejores modelos de IA disponibles para revisar su código en busca de problemas de seguridad — y no encontró este bug.
“Both attackers and defenders have the same AI tools, but today it did not help us, and only helped the bad guys.”
— Coinkite
Esto es “No confíes, verifica” en su forma más cruda. El código abierto no es magia — requiere verificación activa, no transparencia pasiva. El código fue público por más de cinco años. El bug estuvo ahí todo el tiempo. Tomó un atacante con herramientas de IA para encontrarlo.
El Hotfix que Brickea: Un Nuevo Bug en el Fix
El 31 de julio de 2026, Coinkite publicó el firmware hotfix que reemplazó Yasmarang por el TRNG de hardware. El fix era correcto en dirección — rng_get() ahora resuelve al TRNG de hardware del board en lugar del fallback de software. Pero introdujo un bug nuevo que puede brickear el dispositivo permanentemente.
Qué Pasa
El TRNG de hardware del STM32 puede experimentar “seed errors” transitorios — glitches temporales causados por fluctuaciones de voltaje, cambios de temperatura, o ruido eléctrico en el chip. Son eventos normales de hardware, no fallas permanentes. El manual de referencia (RM0432 §25.3.7) documenta el procedimiento de recuperación: limpiar el flag de error SEIS, luego togglear RNGEN off y on.
El código del hotfix no implementa esta recuperación. Cuando ocurre un seed error:
- El flag
SEISse queda pegado (latched) yDRDYdeja de señalizar RNGENsigue activo, así querng_init()considera el periférico “bien” y no hace nada- Cada llamada subsequente a
rng_get()hace timeout a los 10ms y lanzaOSError(EFAULT) - Esto persiste para siempre — a través de reboots de la capa Python
Por Qué Brickea el Dispositivo
Después del hotfix, rng_get() se llama desde el shuffle del orden de escaneo del teclado — la rutina anti-Tempest que aleatoriza el orden en que se escanean las teclas. Esto corre desde un callback de interrupción a hasta 60 Hz, antes del login. Cada keypress triggers 3+ lecturas del TRNG.
Si cualquiera de esas lecturas golpea el estado de fallo del TRNG:
OSErrorpropaga adie_with_debug→show_fatal_error+show_logout- El usuario ve una pantalla de error fatal
- No puede ingresar su PIN
- No puede alcanzar el menú de upgrade
- El dispositivo queda brickeado
Esto coincide con reportes reales de usuarios cuyos Coldcards quedaron “atascados en pantalla de error / no bootea” después de instalar el hotfix.
La Ironía
Antes del hotfix, Yasmarang (el PRNG de software) no podía fallar — siempre producía output, aunque fuera débil. Después del hotfix, el TRNG de hardware sí puede fallar transitoriamente, pero el código no tiene path de recuperación. El fix reemplazó un generador que nunca se caía por uno que puede brickear el dispositivo con un glitch aleatorio de hardware.
Estado Actual
Dos PRs de la comunidad abordan esto:
- PR #692 (Silexperience210): propone
rng_reset()para limpiar flags de error y rehabilitar el periférico, con 3 intentos antes de fallar. También envuelve el shuffle del keypad entry/exceptpara que un fallo de RNG degrade la higiene anti-Tempest en lugar de brickear el login. Solo preventivo — no puede recuperar dispositivos ya brickeados. - PR #693 (scgbckbone, colaborador de Coldcard): un fix alternativo. El colaborador dijo “I think I have something better here.”
Ningún PR se ha mergeado aún. Si no has instalado el hotfix, espera a un firmware que incluya el fix de recuperación del TRNG. Si ya lo instalaste y tu dispositivo funciona, evita generar seeds nuevas con el TRNG del dispositivo — usa el método de solo dados descrito abajo.
El Workaround de Solo Dados
Si necesitas generar una semilla nueva y tu única opción es una Coldcard, puedes bypassar ambos bugs por completo:
- En tu Coldcard, ve a:
New Wallet → Advanced → Dice Rolls - Tira un dado físico de 6 caras 99 veces mínimo (idealmente 100+)
- Ingresa cada tirada manualmente en el dispositivo
- La Coldcard hashea la secuencia de dados directamente para generar la semilla
- Este path no usa Yasmarang ni el TRNG de hardware — los dados son la única fuente de entropía
Con 99+ tiradas de un dado justo, obtienes ~256 bits de entropía (≥128 bits con 50+ tiradas). Este método está documentado oficialmente por Coinkite y bypassa tanto el bug de Yasmarang como el bug de brickeo del hotfix. La secuencia de dados es material de llave secreta — nunca la fotografíes, la guardes digitalmente, ni la ingreses en una computadora conectada a internet.
• No has actualizado: Genera seeds nuevas con 99+ tiradas de dado. Espera a un firmware que incluya tanto el fix de Yasmarang COMO el fix de recuperación del TRNG antes de actualizar.
• Actualizaste y el dispositivo funciona: NO generes seeds nuevas usando el TRNG del dispositivo. Si necesitas una seed nueva ahora, usa solo dados. Espera al próximo firmware estable.
• Actualizaste y el dispositivo se brickeó: Los PRs actuales son preventivos, no curativos. Contacta a soporte de Coinkite.
• Seed creada con 50+ tiradas de dado: Tu seed está SEGURA de esta vulnerabilidad. No necesitas migrar por este bug.
Cómo Verificar si Tu Seed Está Afectada
Paso 1: Identifica Tu Modelo y Firmware
En tu COLDCARD, navega a:
Advanced → Upgrade → Current Firmware Info
Anota el modelo exacto (Mk2, Mk3, Mk4, Mk5, Q) y la versión de firmware.
Paso 2: La Pregunta Crítica
El firmware que tenías cuando generaste la semilla es lo que importa. Actualizar hoy no repara retroactivamente una semilla generada con firmware vulnerable. Compara el modelo de tu dispositivo y la versión de firmware que tenías al generar la semilla contra la tabla “Dispositivos Afectados — Tabla Completa” más abajo. Si tu semilla se generó en cualquier combinación de modelo/firmware marcada como afectada, necesitas migrar a una semilla nueva.
Paso 3: Verifica la Excepción de los Dados
Si usaste “Add Dice Rolls” con 50+ tiradas independientes y privadas al crear tu semilla, tu semilla no está comprometida por este bug — los dados aportan ≥128 bits de entropía por sí solos.
Paso 4: Verifica Tu Passphrase
Un passphrase BIP-39 (no el PIN del COLDCARD) añade una barrera independiente. Si usaste uno fuerte y único, proporciona cierta protección — pero de todos modos debes migrar a una semilla nueva.
Paso 5: Si Estás Afectado, Migra
Si tu semilla está afectada y necesitas migrar, tienes varias opciones:
Opción A: Generar una semilla nueva en tu Coldcard usando solo dados
Puedes crear una semilla segura incluso con firmware afectado — sin actualizar — usando el método de solo dados. Esto bypassa tanto Yasmarang como el TRNG por completo:
- En tu Coldcard, ve a:
New Wallet → Advanced → Dice Rolls - Tira un dado físico de 6 caras 99 veces mínimo (idealmente 100+)
- Ingresa cada tirada manualmente en el dispositivo
- La Coldcard hashea la secuencia de dados directamente para generar la semilla — sin RNG
- Con 99+ tiradas obtienes ~256 bits de entropía (≥128 bits con 50+ tiradas)
Este método está documentado oficialmente por Coinkite. La secuencia de dados es material de llave secreta — nunca la fotografíes, la guardes digitalmente, ni la ingreses en una computadora conectada a internet.
Opción B: Mover fondos a una hardware wallet de otro fabricante
Si tienes acceso a una hardware wallet de un fabricante diferente que genera entropía correctamente, puedes migrar tus fondos ahí:
- Trezor Model T / Safe 5: Usa un TRNG de hardware con firmware de código abierto. También permite añadir entropía con dados durante la generación de la semilla.
- BitBox02: Usa un TRNG de hardware (STM32) con firmware de código abierto.
- SeedSigner: Un signer air-gapped DIY que permite generar semillas con tiradas de dados o fotos de entropía. Totalmente de código abierto.
- Krux: Otro dispositivo air-gapped DIY que soporta generación de semillas con dados. De código abierto.
Siempre verifica que el dispositivo que elijas genere entropía desde un TRNG de hardware, e idealmente que soporte entrada de entropía externa (dados). Investiga el historial del dispositivo y si su firmware es de código abierto.
Opción C: Mover fondos temporalmente a una hot wallet
Si no tienes acceso a una segunda hardware wallet y necesitas mover tus fondos rápido, puedes enviarlos a una hot wallet como medida temporal:
- Usa una wallet de móvil o escritorio de reputación (ej. Blue Wallet, Electrum, Sparrow Wallet)
- Genera una semilla nueva en la hot wallet — estas usan el CSPRNG del sistema operativo, que es criptográficamente sólido
- Mueve los fondos ahí temporalmente hasta que puedas adquirir una hardware wallet con generación de entropía adecuada
Independientemente de la opción que elijas:
- Anota y verifica el nuevo backup, fingerprint de wallet, y una dirección de recepción
- Envía una transacción de prueba pequeña y confirma que llega
- Mueve el resto de los fondos
- Conserva el backup viejo hasta que la migración esté completa y confirmada
Usa un Passphrase — Siempre
Ya sea que uses una hot wallet o una cold wallet, un passphrase BIP-39 es altamente recomendable. Un passphrase (no el PIN del dispositivo) crea un wallet separado encima de tu frase semilla. Incluso si un atacante recupera tu semilla, no puede acceder a tus fondos sin el passphrase.
- Usa un passphrase fuerte y único — no una palabra del diccionario, no una cita, no algo reutilizado
- Guarda el passphrase por separado de las palabras semilla
- Cada passphrase produce un wallet válido — verifica el fingerprint del wallet antes de depositar fondos
- Perder el passphrase significa perder acceso a ese wallet permanentemente
Un passphrase añade una capa independiente de seguridad que te protege incluso si la entropía de la semilla es débil. No es sustituto de entropía adecuada, pero eleva significativamente la barrera para un atacante.
Resumen de Decisión
¿Semilla generada en Mk2/Mk3 v4.0.0–4.1.9? → AFECTADA, migra ¿Semilla generada en Mk4/Mk5/Q antes del fix? → AFECTADA, migra ¿Usaste 50+ dados al crear la semilla? → SEGURA por esta vulnerabilidad ¿Semilla generada en firmware anterior a v4.0.0? → SEGURA ¿Tu dispositivo es TAPSIGNER / OPENDIME / SATSCARD? → NO AFECTADO OPCIONES DE MIGRACIÓN (elige una): A) Semilla nueva en Coldcard con 99+ tiradas de dado (funciona en firmware afectado) B) Mover a una hardware wallet de otro fabricante (Trezor, BitBox02, etc.) C) Mover temporalmente a una hot wallet (Electrum, Sparrow, Blue Wallet) NO instales el hotfix del 31 de julio hasta que salga un firmware con fix de recuperación del TRNG — puede brickear tu dispositivo. USA SIEMPRE un passphrase BIP-39, hot o cold wallet.
La Lección Mayor: La Autocustodia Sigue Siendo Imperativa
Algunos usarán este incidente para argumentar que la autocustodia es peligrosa. Es exactamente lo contrario.
Los exchanges son hackeados, congelan cuentas, y colapsan — FTX, Celsius, BlockFi son solo ejemplos recientes. Cuando no es tu llave, no es tu Bitcoin. Este bug se encontró, se documentó públicamente, y se parchó — porque el código era abierto y la comunidad pudo auditarlo. Intenta exigir ese nivel de transparencia a un exchange centralizado.
La autocustodia es imperativa. Pero requiere responsabilidad activa:
- Verifica tu versión de firmware
- Considera añadir entropía con dados al generar semillas
- Mantén backups verificados
- Migra con calma cuando se descubren vulnerabilidades, no con pánico
- Usa multisig con quorums de dispositivos independientes y seguros
“Sé tu propio banco” no es un eslogan — es un compromiso con la seguridad que nadie más puede asumir por ti.
El bug estuvo en el código por más de cinco años. El código era abierto. Nadie lo encontró hasta que un atacante lo hizo. Esa es la realidad de la seguridad de código abierto: la transparencia es necesaria pero no suficiente. Habilita la verificación — no la reemplaza.
La autocustodia sigue siendo la única forma de ser verdaderamente soberano sobre tu Bitcoin. Este incidente no cambia eso. Lo refuerza.
Referencias
- Aviso de Seguridad de Coinkite — Mk3 Seed Generation Warning
- Coinkite Technical Backgrounder — Entropy Issue
- Block Engineering — Predictable RNG Fallback and 32-Bit Reseed in COLDCARD Firmware
- Código fuente del fallback RNG de MicroPython (fork de Coinkite)
- Implementación de RNG en Libngu
- Commit que introdujo la regresión (marzo 2021)
- LLFOURN: Modelo de costo de ataque para generaciones afectadas de COLDCARD
- PR #692: rng: recover the TRNG after a seed/clock error instead of failing forever
- PR #693: Fix alternativo de recuperación del TRNG (scgbckbone)
- Coinkite: Documentación de generación de semilla con dados
