ColdCard Hack — O Bug que Quebrou o Cofre
Em 30 de julho de 2026 a ColdCard foi hackeada. Não gradualmente. Não apenas teoricamente. Em menos de 41 minutos, 1.196 endereços foram drenados.
Quando a Propriedade Privada do Código Quebrou o Cofre
A frase "not your keys, not your coins" foi o mantra sagrado da comunidade Bitcoin por anos. A ideia é simples: você é seu próprio banco. Seus Bitcoin são seus. Ninguém toca neles. A chave privada é a soberania.
Mas e se a carteira de hardware, o cofre, é o problema?
Nota do autor: Pessoalmente não costumo utilizar o termo cofre, prefiro o termo assinador (que é exatamente o que esses dispositivos fazem). Mas para fins deste artigo, utilizarei o termo cofre ao invés de carteira ou wallet porque é como a ColdCard era vista no ecossistema.
Em 30 de julho de 2026, às 01:10 UTC, o cofre quebrou. Não gradualmente. Não apenas teoricamente. Entre 01:10 e 01:51 UTC (menos de 41 minutos), 1.196 endereços foram drenados, consolidados em 4 endereços. De forma brutal. De forma real. De forma irreversível.
E a causa não foi um ataque externo. Não foi uma falha de segurança na rede Bitcoin. Não foi um bug no blockchain.
A causa foi um #define mal escrito.
O Bug que Começou com uma Linha de Código
As ColdCard Mk3 e Mk4, as carteiras que mais se venderam para Bitcoiners, têm um microprocessador STM32 com um gerador de números verdadeiramente aleatórios (TRNG) integrado. O firmware lia esse TRNG para gerar a entropia que viraria sua seed phrase. A ideia era sólida: hardware dedicado, sem interferência de software.
Mas em março de 2021, a Coinkite, a empresa que fabrica a ColdCard, fez uma mudança. Um rewrite. Uma reescrita completa do firmware que eliminou o código aberto GPL, trocou bibliotecas criptográficas por outras próprias, e fez toda a geração de seed passar por um novo runtime chamado libngu.
A mudança era complexa. E em meio à complexidade, um desenvolvedor escreveu:
#define MICROPY_HW_ENABLE_RNG (0)
Dentro do libngu, havia um guardião que protegia a geração de seed:
extern uint32_t rng_get(void);
#define CHIP_TRNG_32() rng_get()
#ifndef MICROPY_HW_ENABLE_RNG
#error "get a HW TRNG plz"
#endif
Se o guardião #ifndef não encontrasse o macro MICROPY_HW_ENABLE_RNG, ele gritaria: o compilador exibiria a mensagem de erro, e a build pararia. A mensagem era clara: sem TRNG de hardware, a build falha.
Mas a lógica do #ifndef é binária. Ele checa a existência do macro, não seu valor. E como o macro existia, mesmo que seu valor fosse 0, o guardião não gritou. A build passou. Silenciosamente.
Quando o MICROPY_HW_ENABLE_RNG é 0, a MicroPython cai no fallback: o gerador pseudoaleatório de software chamado Yasmarang.
A Queda para o Pseudo-Aleatório
O Yasmarang é um gerador pseudoaleatório de 32 bits criado por Ilya Levin para sistemas embarcados. Não serve para criptografia de wallets. Ele é determinístico. Mantém um estado interno de quatro variáveis (pad, n, d, dat) e, quando chamado, gera uma sequência previsível.
O firmware da ColdCard inicializa o Yasmarang com:
pad = UID_low32 ^ SysTick->VAL;
n = RTC->TR;
d = RTC->SSR;
dat = 0;
Essas variáveis não são aleatórias. São determinísticas:
UID_low32é o identificador único do chip (estático, parcialmente exposto em metadata USB)SysTick->VALé o down-counter do processador (previsível durante a inicialização)RTC->TReRTC->SSRsão o relógio de tempo real e seu sub-segundo (previsíveis durante a inicialização)
Uma vez semeado com esses valores, o Yasmarang não gera mais entropia; cada saída é uma transição matemática de estado.
O libngu tenta esconder isso XORando a saída com uma segunda instância do Yasmarang, mantida internamente com constantes estáticas:
static uint32_t yasmarang_pad = 0x0a8ce26f;
static uint32_t yasmarang_n = 69;
static uint32_t yasmarang_d = 233;
static uint8_t yasmarang_dat = 0;
Cada saída de palavra é calculada como:
chip = rng_get(); // MicroPython fallback
chip ^= my_yasmarang(); // libngu Yasmarang
XOR não cria entropia. Se ambas as entradas são reprodutíveis, seu XOR é reprodutível.
O Commit que Introduziu o Bug
O bug de entropia foi introduzido no commit b18723dd ("First pass w/ libNgU") em 1 de março de 2021, em 120 arquivos alterados (2766 linhas adicionadas, 2722 deletadas).
Antes do Rewrite: Trezor Crypto Library
Antes desse commit, o firmware v3.2.2 gerava a entropia da seed com:
seed = bytearray(32)
rng_bytes(seed)
Esse caminho alcançava ckcc.rng_bytes e o TRNG de hardware STM32 local. Crucialmente, o firmware v3.2.2 estava funcionando corretamente. Não tinha falha de entropia. O TRNG de hardware funcionava como projetado.
O Rewrite e as Bibliotecas da Trezor
Depois do commit b18723dd, a geração de seed mudou para:
seed = random.bytes(32)
shared/random.py redirecionava essa chamada para ngu.random.bytes. A mudança apareceu no firmware liberado v4.0.0, em 17 de março de 2021.
Mais importante: o rewrite apagou explicitamente as bibliotecas criptográficas derivadas da Trezor. O commit mostrou a remoção de dois submodules relacionados ao Trezor:
- [submodule "external/modcryptocurrency"]
- [submodule "external/crypto"]
path = external/crypto
url = https://github.com/peter-conalgo/trezor-crypto.git
O trezor-crypto é a biblioteca criptográfica própria da Trezor, desenvolvida por SatoshiLabs como fork do libsecp256k1. Ela contém implementações específicas para Bitcoin: base58, hashing, curvas elípticas, e muito mais.
O modcryptocurrency era uma versão forkada do modtrezorcrypto (bindings MicroPython para a biblioteca criptográfica da Trezor). Era a ponte que permitia que o firmware MicroPython chamasse as funções criptográficas da Trezor diretamente.
O Novo Stack: libngu e o Soft RNG Fallback
Com a remoção dessas bibliotecas, a ColdCard introduziu o libngu, um novo runtime criptográfico escrito internamente pela Coinkite. O commit também adicionou:
[submodule "external/libngu"]
path = external/libngu
url = https://github.com/switck/libngu.git
O bug foi introduzido não pelo libngu em si, mas pelo fato de que o guardião de verificação (#ifndef) aceitou o macro MICROPY_HW_ENABLE_RNG definido como 0 sem validar seu valor.
Quando o TRNG de hardware não estava disponível (ou quando o guardião falhou), o código caiu para o fallback Yasmarang, um gerador pseudoaleatório de 32 bits.
O trezor-crypto e o modtrezorcrypto eram bibliotecas maduras, auditadas, e testadas extensivamente pelo ecossistema Bitcoin.
A Tentativa de Mitigação Incompleta (Mk4/Mk5)
Para os dispositivos mais recentes (Mk4, Mk5 e Q), com o commit 01cb43f ("Seed RNG with RNG from both SE's") em 11 de março de 2022, foi introduzida uma função chamada rng_seeding() no arquivo shared/mk4.py:
def rng_seeding(): # seed our RNG with entropy from secure elements import callgate, ngu, ustruct
a = callgate.read_rng(1) # SE1
b = callgate.read_rng(2) # SE2
n = ngu.hash.sha256d(a+b)
n, = ustruct.unpack('I', n[0:4])
ngu.random.reseed(n)
Essa função lia bytes aleatórios dos dois Secure Elements, combinava-os, calculava SHA256d, e então mantinha apenas 4 bytes (32 bits) do hash resultante. O restante da entropia (os outros 224 bits) era descartado.
O problema era duplo:
- Apenas um 32-bit word era passado para
ngu.random.reseed(), que atualizava apenas a palavrayasmarang_pad:
STATIC mp_obj_t
random_reseed(mp_obj_t arg) {
yasmarang_pad = mp_obj_get_int_truncated(arg);
return mp_const_none;
}
- Nenhum dos outros estados era recalibrado. Mas ao contrário do que se imagina,
yasmarang_n,yasmarang_deyasmarang_datnão estavam nos valores fixos da Yasmarang (69,233,0), estavam inicializados a partir de registradores do MCU:
pad = *(uint32_t *)MP_HAL_UNIQUE_ID_ADDRESS ^ SysTick->VAL;
n = RTC->TR; // registrador de tempo
d = RTC->SSR; // registrador de sub-segundos
O reseed(s) sobrescrevia pad com o seed de 32 bits, mas mantinha n e d congelados nos valores do RTC no momento do boot.
Para um estado de fallback fixo F (quando o atacante conhece todos os valores de RTC/UID) e um histórico de chamadas T:
|| output(R, F, T) : R ∈ [0, 2^32) || ≤ 2^32
O estado interno pode espalhar esses 32 bits pela saída posterior, mas não pode criar entropia adicional além do que entrou.
No pior caso (atacante conhece F completamente), a entropia segura fica limitada a 2^32, apenas 32 bits.
Na prática, como F contém valores do RTC e do UID do MCU que o atacante precisa descobrir, a entropia efetiva total é de aproximadamente 72 bits, ainda muito abaixo dos 256 bits que eram o alvo de segurança declarado.
A Matemática Implacável
Uma seed phrase de 24 palavras tem 256 bits de entropia. Isso significa 2^256 combinações. Um número maior que a idade do universo multiplicada por si mesma. Inacessível.
Mas a ColdCard não tinha 256 bits, tinha 40 bits de entropia real em Mk3, e 72 bits em Mk4/Mk5.
Com uma GPU moderna, é possível calcular 2^40 derivações ECDSA em minutos para Mk3. Para Mk4/Mk5, a conta é semanal a anual, ainda vulnerável, mas numericamente mais forte.
Para contextualizar, vamos comparar as seed phrases de 12 e 24 palavras:
12 palavras = 128 bits de entropia → 2^128 ≈ 3,4 × 10^38 combinações. Com um supercomputador moderno testando 10^17 combinações por segundo, levaria cerca de 10^14 anos, 10.000 vezes a idade do universo.
24 palavras = 256 bits de entropia → 2^256 ≈ 1,1 × 10^77 combinações. Com o mesmo supercomputador, 10^52 anos. Um número inimaginável.
A diferença entre 40 bits e 128 bits não é apenas de grau, é de ordem de magnitude.
Com 40 bits? A conta é brutal. 2^40 = 1.099.511.627.776 combinações possíveis (cerca de 1,099 trilhão). Com GPUs modernas testando milhões de derivações de chave por segundo, isso leva minutos.
Com 72 bits? 2^72 = 4.722.366.482.869.645.213.696 combinações (cerca de 4,7 sextilhões). Com o mesmo cluster, isso leva semanas a anos, o que explica por que o ataque foi focado em dispositivos Mk3, que tinham o espaço de busca mais amplo (2^40).
A Execução do Ataque
A exploração silenciosa da vulnerabilidade culminou em 30 de julho de 2026 (entre 01:10 e 01:51 UTC) com um saque de 1.082,65 BTC (~$70 milhões) em menos de 41 minutos.
A operação foi executada em quatro blocos consecutivos (bloco 960.183 até 960.191) com 1.196 endereços de 1.324 UTXOs consolidados em 4 endereços principais. O atacante não usou software de carteira padrão: operou inteiramente por scripts automatizados, evidenciado pela taxa uniforme de 30 sats por byte virtual (sat/vB) em cada transação, 30 a 75 vezes acima da taxa média da época (0,4–1,0 sat/vB). Ao pagar propinas exorbitantes, o atacante garantiu inclusão imediata no próximo bloco, neutralizando qualquer tentativa de vítimas ou serviços de monitoramento de usar RBF (Replace-By-Fee) para recuperar os fundos.
Os endereços drenados eram todos de arquitetura single-signature. O atacante também instituiu um piso de rentabilidade: nenhum endereço drenado continha menos de 0,15 BTC. A perda mediana foi de 0,41 BTC, com o maior victim tendo perdido 29,9 BTC (quase US$ 2 milhões).
O piso de 0,15 BTC indica que o atacante estava otimizando recursos computacionais. Derivar chaves públicas e verificar saldos para cada possível seed de 40 bits (Mk3) requer overhead computacional significativo; o filtro foi automático.
Pesquisadores de segurança como Kevin Loaec, CEO da Wizardsardine, teorizam que o atacante usou IA e frameworks de criptoanálise avançada para determinar o path derivation. Quando uma seed mestre é derivada, software de carteira gera milhares de endereços potenciais (BIP-44, BIP-49, BIP-84). Os dados on-chain mostram que 1.183 dos 1.196 endereços eram Native SegWit (BIP-84), com impactos marginais em formatos mais antigos (7 BIP-49, 6 BIP-44). O atacante provavelmente otimizou seus cálculos para os paths mais comuns para maximizar velocidade.
O ataque também foi diferenciado por seu escopo: 419 endereços tinham um único UTXO cada, mas um tinha acumulado 200 UTXOs e outro 105, um padrão típico de alguém recebendo compras recorrentes ou retiradas automáticas de exchange sempre para o mesmo endereço. A taxa total da operação foi de aproximadamente 0,044 BTC.
Nenhum endereço de multisig e nenhum endereço taproot estava entre as vítimas.
A consolidação ocorreu imediatamente e os fundos permaneceram estáticos:
- bc1qq85v2c926eg6pgxhwp6q7lf6cnsz80qs3fcu9r : 562,02 BTC
- bc1qx76cae2706qd5q576feh7xq8rfcsjpf2htfhe3 : 398,48 BTC
- bc1q8jy96fe5lf8vfugydnte3cguk92gpev7kwtp3q : 89,62 BTC
- bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0 : 32,45 BTC (não movido)
Todos os fundos não se moveram desde as consolidações em julho de 2026 até o momento em que este texto é escrito.
A Resposta
A Coinkite respondeu: primeiro minimizando o problema, depois assumindo a responsabilidade após a equipe de engenharia de segurança da Block revelar sua engenharia reversa do libngu.
Os patches foram liberados:
- ColdCard Mk3: versão 4.2.0 ou posterior
- ColdCard Mk4 & Mk5: Standard 5.6.0 ou Edge 6.6.0X
- ColdCard Q: Standard 1.5.0Q ou Edge 6.6.0QX
Mas atualizar o firmware não conserta a seed. O patch garante que wallets geradas a partir de agora usarão a entropia correta, mas não muda a fraqueza de uma seed gerada sob firmware vulnerável.
A migração é obrigatória: atualize o firmware, gere uma nova seed (de preferência com dados), verifique, restaure a seed antiga, faça um teste de transação, e depois mova os fundos para a nova seed.
12 vs 24 Palavras: O Que o Hack da ColdCard Revelou
O hack da ColdCard traz à tona uma discussão que já vinha sendo feita por anos: seed de 12 ou 24 palavras?
A resposta é simples: o argumento de que 12 palavras já é suficiente perde toda a força quando a entropia do dispositivo é comprometida.
Quando a ColdCard tinha 72 bits de entropia em Mk4/Mk5 em vez dos 256 bits esperados de uma seed de 24 palavras (ou 128 bits para uma seed de 12 palavras), a segurança não era apenas reduzida, era aniquilada. A diferença entre 256 bits e 72 bits não é uma questão de grau, é uma diferença de ordem de magnitude.
Para entender a profundidade do problema, considere os números:
A tabela diz tudo. A ColdCard Mk3, a carteira mais popular do ecossistema Bitcoin, era menos segura que uma senha de 12 dígitos numéricos. O Mk4/Mk5, embora numericamente mais forte, ainda apresentava uma fragilidade significativa.
A Causa: Propriedade Privada vs Colaboração
O bug não foi introduzido em uma linha de código isolada. Foi o resultado de uma sequência de escolhas que começou com uma atitude fundamentalmente equivocada sobre o open source.
O Rewrite e as Bibliotecas da Trezor
O commit b18723dd ("First pass w/ libNgU") introduziu uma mudança monumental: ele removeu explicitamente as bibliotecas criptográficas derivadas da Trezor:
- [submodule "external/modcryptocurrency"]
- [submodule "external/crypto"]
path = external/crypto
url = https://github.com/peter-conalgo/trezor-crypto.git
O trezor-crypto é a biblioteca criptográfica própria da Trezor, desenvolvida por SatoshiLabs como fork do libsecp256k1. O modcryptocurrency era uma versão forkada do modtrezorcrypto (bindings MicroPython para a biblioteca criptográfica da Trezor).
Essas bibliotecas eram maduras, auditadas, e testadas extensivamente pelo ecossistema Bitcoin.
Julho 2020: Foundation Devices usa o firmware GPL da ColdCard na Passport
Em julho de 2020, a Foundation Devices, liderada por Zach Herbert, lançou a Passport, uma carteira de hardware que usou o firmware GPL da ColdCard como base. A Passport era bonita, tinha câmera para QR codes air-gapped, e era uma carteira funcional. E, crucialmente, ela revisou, auditou e melhorou o código ao usar como base.
A Trezor e a Ledger também têm uma história de usar bibliotecas criptográficas de código aberto, e ninguém reclamou.
Mas quando a Foundation fez o mesmo, a reação foi diferente.

A Foundation Devices declarou que a Passport seria baseada no firmware GPL da ColdCard. O próprio fundador da ColdCard, NVK, foi claro sobre sua frustração: "Eu realmente me arrependo de escolher GPLv3 para a ColdCard. Agora temos um clone com zero contribuições em código/financeiramente." (veja mais na entrevista com os Bitcoinheiros em 2020 [16]).
Essa frase diz muito. Ela revela uma crença que chamamos de "propriedade privada do código": a ideia de que se alguém usa seu código, você está sendo prejudicado, e não como tendo um benefício.
Na verdade, se um projeto usa seu código, revisa ele, audita ele, e eventualmente o melhora ou colabora com você, todos ganham. Esse é o espírito do software livre. Ele multiplica o valor, não se reserva para um único proprietário.
Outro ponto que temos que recordar é que a própria ColdCard se beneficiou de código aberto da Trezor como base para a sua concepção, uma clara contradição.
A Escolha de Design: Fechar o Código
Em cerca de 100 commits, a Coinkite fechou o código, mudou de GPL para MIT+Creative Commons, removeu bibliotecas criptográficas open source, e introduziu o libngu. E com o libngu, a falha foi introduzida.
O rewrite foi apressado porque NVK não aceitava que outras pessoas usassem seu código. Ele queria controle. Ele queria impedir que outros se beneficiassem e, ironicamente, acabou impedindo que todos se beneficiassem, incluindo ele mesmo.
O firmware v3.2.2, antes dessa mudança, não tinha esse bug. O TRNG de hardware funcionava corretamente. A entropia era real. O problema apareceu apenas depois que o código foi fechado, os componentes FOSS foram removidos e um novo runtime foi implementado em um rewrite apressado.
Recomendações de Segurança
Com base neste evento:
1. Gere sua seed com dados físicos: Jogue dados, role dados, jogue uma moeda. Não confie no gerador pseudoaleatório de um dispositivo, mesmo naquele que parece seguro. Um ambiente air-gapped, offline, sem internet, sem malware, e uma seed gerada por entropia verificável. Não é uma escolha de conforto. É um imperativo de sobrevivência. Quando o atacante teve acesso aos dados da ColdCard, ele só precisou quebrar confiança.
2. Use seed de 24 palavras: A entropia de 256 bits do BIP39 é a base real da segurança da chave privada. A escolha entre uma seed phrase de 12 ou 24 palavras é crucial para a segurança de suas criptomoedas. A recomendação clara é optar por 24 palavras, apesar do pequeno inconveniente de registrar mais palavras. A compensação é uma segurança exponencialmente maior.
3. Adote multi-sig: Se você tem volume, multi-sig com diferentes fabricantes neutraliza o problema de um único fornecedor comprometido. Cada um vai ter seu algoritmo, seu cálculo; você não fica sujeito a uma marca, uma técnica, um método. O atacante drenou todos os endereços single-signature. Não houve diversificação.
4. Use passphrase forte: O BIP-39 passphrase (a "25ª palavra") aumenta a segurança, mas apenas se a passphrase for forte. Cada bit adicional dobra a segurança. Uma passphrase fraca, uma senha de dicionário, "1998", "natal2024", é pior que inútil: ela é falsa segurança.
5. Atualize seu firmware e verifique seu backup: Se você ainda tem um ColdCard Mk2, Mk3 ou Mk4 com firmware anterior ao patch, mova seus fundos para um dispositivo com seed gerada por entropia verificável. Mas não confie que isso conserte o passado: a seed que você gerou sob firmware vulnerável permanece fraca, mesmo que você atualize depois. A migração é obrigatória, mas não mágica.
6. Entenda a diferença entre Mk3 e Mk4/Mk5: O bug era mais severo em Mk3 (40 bits de entropia) do que em Mk4/Mk5 (72 bits). Se você tem um Mk4 com firmware atualizado após o patch de março de 2022, seu risco é menor, mas ainda presente. O firmware v3.2.2 (antes do commit b18723dd) não era vulnerável.
7. Não dependa de uma única fonte: O que aconteceu com a ColdCard é um lembrete: quando o código não é livre, a comunidade não tem incentivos para auditar. Bugs ficam escondidos. A melhor defesa é diversificar multi-sig, vários fabricantes, e conhecimento profundo do que você está usando.
A Conclusão: Código Fechado = Cofre Aberto
Quando você transforma software livre em "código disponível" (visível, mas não livre), você quebra o ciclo de incentivo que mantém o código seguro. Quando o código não é livre, o mercado deixa de contribuir, de auditar, de melhorar. E os bugs permanecem invisíveis até que alguém já tenha drenado 1.196 carteiras em 41 minutos.
A ColdCard não foi simplesmente hackeada. Foi consequência. Uma consequência direta de uma escolha de design, uma escolha de licença, e uma atitude.
A sequência é clara:
- Julho 2020: Foundation Devices usa o firmware GPL da ColdCard na Passport
- Reação emocional: NVK decide que "seu código" é propriedade que ele deve proteger
- Março 2021: ColdCard fecha o código, muda de GPL para MIT+Creative Commons, remove componentes FOSS, e introduz o libngu
- Bug introduzido: O rewrite apressado não tinha QA suficiente, e o guardião de verificação (#ifndef) aceitou o macro definido como 0 sem validar seu valor
- Julho 2026: O bug permanece invisível por três anos até ser explorado: 1.196 carteiras drenadas em 41 minutos
A pergunta que fica: você confia no seu cofre?
A resposta depende do que você sabe sobre o cofre e de quanto tempo você está disposto a passar lendo o código do cofre.
E a melhor prática: gere sua seed com dados (em um ambiente air-gapped, offline, sem internet, sem malware) e importe para o seu cofre.
Assim, não importa o que aconteça, você não depende do cofre. Você depende da entropia.
Referências
- A Security Focused Outline on Bitcoin Wallets
- Predictable RNG Fallback and 32-Bit Reseed in COLDCARD Firmware (Block Engineering)
- BIP-39: Mnemonic code for generating deterministic keys
- BIP-32: Hierarchical Deterministic Wallets
- A flaw in Coldcard seed generation lets attackers recreate private keys from the press of a button (CryptoSlate)
- Seed de 12 ou 24 palavras? (Autor original, eddieoz.com)
- Commit b18723dd ("First pass w/ libNgU"), Coldcard/firmware (1 de março de 2021)
- Commit 01cb43f7 ("Seed RNG with RNG from both SE's"), Coldcard/firmware (11 de março de 2022)
- Commit f32e057 ("Signed for MK3 release"), Coldcard/firmware (31 de julho de 2026)
- ColdCard Security Advisory
- Galaxy Research: Mapping the flow of funds for the Coldcard vulnerability (Jul 31, 2026)
- Mempool.space: Address bc1qq85v2c926eg6pgxhwp6q7lf6cnsz80qs3fcu9r (Confirmed balance: 562,02 BTC)
- Mempool.space: Address bc1qx76cae2706qd5q576feh7xq8rfcsjpf2htfhe3 (Confirmed balance: 398,48 BTC)
- Mempool.space: Address bc1q8jy96fe5lf8vfugydnte3cguk92gpev7kwtp3q (Confirmed balance: 89,62 BTC)
- Mempool.space: Address bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0 (Confirmed balance: 32,45 BTC)
- Entrevista com o fundador da Coinkite (YouTube Bitcoinheiros) (Why GPL to Proprietary, 2020)
