← Terug naar alle inzichten

Op 30 juli 2026 begon iemand Coldcard-wallets leeg te halen. De eerste golf trof er 1.196 in eenenveertig minuten. De gemelde schade loopt inmiddels van 88 tot 130 miljoen dollar.

Er werd niet gehackt. Geen apparaat gestolen, geen herstelzin gefotografeerd, geen server gekraakt. De sleutels werden simpelweg geraden.

Ze waren te raden door een programmeerfout die in maart 2021 werd uitgebracht en daar vijf jaar bleef zitten. In plaats van de speciale willekeurchip in het apparaat gebruikten getroffen Coldcards stilletjes een veel zwakkere bron. Daardoor waren de wallets die ze bouwden ruwweg 72 biljard keer makkelijker te raden, en niemand merkte het, totdat iemand begon te raden.

Eén groep bleef ongemoeid. Wie minstens vijftig keer met de hand had gedobbeld, zat goed, want die worpen leverden al genoeg echte willekeur. De mensen die het paranoïde ding deden, waren de enigen die veilig waren.

Waarom niemand het vijf jaar lang merkte

Je wallet is één getal. Elk adres dat je bezit en elke sleutel die je munten uitgeeft, wordt daaruit berekend. De twaalf of vierentwintig woorden die je opschreef staan daar niet los van. Ze zijn dat getal, in een vorm die een mens zonder typefouten kan overnemen. Die woorden heten je zaad.

Het getal is 256 bits lang, en een bit is één muntworp. Stel je dus voor dat je 256 keer een munt opgooit en het resultaat opschrijft. Dat is je wallet, en je beveiliging hangt aan één vraag: kan iemand anders die worpen raden?

Om ze te maken verzamelt een apparaat iets onvoorspelbaars: een ruischip, een camera of dobbelstenen die je zelf werpt. Daarna gaat alles wat het verzameld heeft door een blender, een hashfunctie, die van elke invoer een schoon resultaat van 256 bits maakt. In die blender zit de val.

Die laat alles willekeurig lijken. Stop het woord "banana" erin en er komt een getal van 256 bits uit zonder enig zichtbaar patroon. Het zou elke statistische toevalstest doorstaan die ooit geschreven is. Het is ook in één poging te raden door iedereen die aan het woord "banana" denkt.

De regel die je moet onthouden

Toevalstests meten hoe het resultaat eruitziet. Ze kunnen niet meten of iemand het kan voorspellen. Elk getroffen Coldcard-zaad zag er onberispelijk uit.

Dit is geen randmening. NIST, het Amerikaanse instituut naar wiens normen het grootste deel van de beveiligingsindustrie werkt, zei het in 2010 al in zijn eigen handleiding over toevalstests: deze tests kunnen je niet vertellen dat een generator veilig is. NIST herschrijft die handleiding nu juist om dat te ontmoedigen. Eén strengere norm werkt wel, maar alleen op de ruwe ruis zoals die was vóór de blender, en dat is nu juist het enige wat een afgewerkte wallet je nooit laat zien.

Je eigen zaad testen is dus een doodlopende weg. Er blijft één vraag over: kun je het getal zelf reproduceren, uit iets wat jij in de hand had en kunt narekenen? Ik las de code van zes wallets om uit te zoeken wie je dat toestaat.

Wat ik vond

Zes dingen, uit de firmware in plaats van uit de documentatie, op een vaste versie. Niets ervan is een noodgeval, en onderaan is elke bevinding beoordeeld.

1. SeedSigner knijpt de willekeur uit zijn eigen foto

SeedSigner kan een zaad bouwen uit een camerabeeld: vijftig snelle voorbeeldframes plus één uiteindelijke foto op volle resolutie, door elkaar gemengd. De vijftig voorbeelden gaan er precies zo in als de sensor ze maakte. De uiteindelijke foto niet. Die wordt eerst als JPEG opgeslagen en daarna weer geopend, en JPEG werkt door fijne details weg te gooien die je oog toch niet mist. Fijne details zijn precies waar cameraruis zit, en die ruis is de hele reden om een camera ergens op te richten. De code noemt die foto "our headline entropy". Het is het enige ingrediënt dat vóór gebruik is uitgewrongen.

Je zaden zijn in orde. De vijftig onaangeroerde frames gaan er als eerste in en dragen de echte willekeur, en willekeur die er eenmaal in zit, krijg je er niet meer uit. De fout is dat het apparaat trots is op het verkeerde ingrediënt.

2. De SeedSigner die je vandaag kunt installeren controleert zijn eigen camera niet

De volgende versie eist vijftig werkelijk verschillende frames en weigert lege. Die controles zijn op 8 augustus toegevoegd. De huidige uitgave, 0.8.7, kwam uit op 9 juni. Op de versie die mensen echt draaien levert een afgedekte lens of een bevroren camera dus nog steeds een zaad op, en niets waarschuwt je.

Van alles hier is dit degene die ik het liefst opgelost zou zien.

3. Jade mengt vijf nullen in en noemt ze sensormetingen

Blockstream Jade roert sensormetingen door zijn willekeur: batterijspanning, USB-stroom, temperatuur en nog drie andere. Op de huidige Jade v2-hardware zijn vijf van die zes sensoren zo geschreven:

uint16_t power_get_iusb(void)  { return 0; }
uint16_t power_get_temp(void)  { return 0; }

Je hoeft geen C te kunnen lezen. Beide functies geven het getal nul terug, elke keer weer, en nul is geen willekeur.

Blockstreams marketing spreekt over het meemengen van knopdrukken, dobbelsteenworpen en omgevingstemperatuur. Er is geen code voor knopdrukken, helemaal geen code voor dobbelstenen, en temperatuur is die vastgezette nul. Jade is niet stuk, want de echte willekeur komt ergens anders vandaan. Maar de verdedigingslagen zijn dunner dan ze lijken.

4. Trezor controleert alleen de wallets die het weggooit

Trezor heeft iets werkelijk slims gebouwd. Voordat jouw computer zijn eigen willekeur stuurt, moet het apparaat zijn antwoord in een envelop verzegelen, zodat het niet bij het jouwe kan gluren en zich kan aanpassen. Jouw computer opent die envelop daarna en controleert of de wallet echt uit de inhoud is gebouwd. Daarna herhaalt het zich, een geheim aantal keer tussen twee en acht.

In de laatste ronde wordt de envelop nooit geopend. Elke ronde die wél gecontroleerd wordt, is een wallet die daarna wordt weggegooid, en de wallet waar je mee wegloopt is degene die niemand heeft gecontroleerd. Dat is bewust, en de redenering houdt stand: een oneerlijk apparaat kan niet weten welke ronde de laatste is, dus moet het gokken en wordt het waarschijnlijk betrapt.

Het maakt valsspelen een verliezende weddenschap. Wat het niet doet, is bewijzen dat je zaad eerlijk is, en zo wordt het meestal wel omschreven.

5. Krux beoordeelt je dobbelstenen, en dat oordeel is te misleiden

Krux is het enige apparaat dat je worpen beoordeelt en waarschuwt als ze er verkeerd uitzien. Die waarschuwingen kun je wegklikken, en ze missen een voor de hand liggende truc. Werp tien keer eerlijk en kopieer dat blok vijf keer om je vijftig vol te maken. Je hebt ongeveer 26 bits geleverd, ongeveer een kort wachtwoord. Krux meldt er 126 en zegt niets.

De eigen handleiding geeft toe dat de score geen garantie is. Het risico zit in het gat tussen die handleiding en een groene voortgangsbalk voor je neus. Krux is ook het enige apparaat dat zijn rekenwerk laat zien, en dat is hier de beste gewoonte.

6. OneKey heeft de bescherming die het erfde nooit overgenomen

De firmware van OneKey is gebouwd op die van Trezor. In januari 2025 voegde Trezor het envelopsysteem hierboven toe, zodat een apparaat niet kan valsspelen door te reageren op de willekeur van jouw computer. OneKey splitste zich af in mei 2022 en heeft die update nooit overgenomen.

Het bewijs is één berichtdefinitie, in hetzelfde bestand in beide projecten:

Trezor:  message EntropyRequest {
             optional bytes entropy_commitment = 1;
             optional bytes prev_entropy = 2;
         }

OneKey:  message EntropyRequest {
         }

Leeg. Zoeken in de volledige codebase van OneKey naar dat belofteveld levert helemaal niets op.

Dit geldt voor elk huidig OneKey-apparaat, in code van juni 2026. Een wallet die verkocht wordt als het open source alternatief mist de bescherming die de bron ervan juist voor dit probleem heeft gebouwd.

Waar ik het mis had, en dat is goed nieuws

Ik verwachtte dat dobbelsteenback-ups vastzaten aan het merk dat ze had gemaakt, zodat je opgeschreven worpen waardeloos zouden zijn op elk ander apparaat. Dat klopt niet.

Geef ze alle drie dezelfde dobbelstenen en je krijgt dezelfde woorden terug

SeedSigner, Krux en de dobbelsteenmodus van Coldcard doen precies hetzelfde met je worpen. Ze hashen de cijfers als gewone tekst, zonder er iets aan toe te voegen. Ik heb dat gecontroleerd in plaats van iemand op zijn woord te geloven, door de zes testvectoren na te rekenen die die projecten publiceren. Alle zes kwamen goed uit.

Je kunt hetzelfde doen, met een commando dat al decennia met Linux meekomt:

printf '65515223131652132161133154444123616466443112153441' | sha256sum

Die vijftig cijfers zijn vijftig dobbelsteenworpen, en wat eruit komt is het zaad dat je wallet daaruit zou bouwen. Gebruik printf in plaats van echo, want een verdwaalde regelovergang verandert het antwoord volledig.

Toen controleerde ik Keystone, en die is het er niet mee eens.

Keystone schrijft elke 6 om naar een 0 vóór het hashen. De andere drie hashen de cijfers precies zoals je ze hebt ingetikt. Dezelfde vijftig worpen bouwen dus twee verschillende wallets:

hashed as typed   ->  hole luggage safe present express tragic...
6 rewritten as 0  ->  tip toward alcohol rule pave weird...

Dezelfde vijftig dobbelsteenworpen, en aan geen van beide reeksen woorden zie je welke afspraak hem heeft gemaakt.

De veelgebruikte browsertool van Ian Coleman zit in het kamp van Keystone en schrijft de 6 om in zijn eigen broncode. Er zijn dus twee afspraken in plaats van één standaard, en je apparaat vertelt je niet welke het volgt. Opgeschreven worpen werken alleen op een wallet uit hetzelfde kamp.

Dat terzijde blijft dit het nuttigste feit hier. Een zaad dat met dobbelstenen is gemaakt, kun je narekenen op een laptop die je al hebt, en je hoeft niemand op zijn woord te geloven behalve de rekenkunde. Let bij Coldcard op dat dit geldt voor de modus met alleen dobbelstenen, niet voor de nieuwere standaardmodus die apparaatwillekeur meemengt.

Waar het op neerkomt

Verschillende van deze bedrijven hebben slimme bescherming gebouwd tegen een oneerlijk apparaat dat je transacties vervalst. Bijna niets daarvan beschermt het zaad, het ene getal waar al het andere van afhangt.

De Coldcard-fout laat zien wat dat gat kost, één keer, in het openbaar, voor ruim 88 miljoen dollar. De oorzaak was één regel code die controleerde óf een instelling bestond, in plaats van waarop die stond.

Je kunt je hier niet uit testen. Je kunt alleen weigeren degene te zijn die moet vertrouwen. Vijftig dobbelstenen en één commando is hier de enige methode die je zover brengt.

Hoe ernstig is dit allemaal?

Niet erg, en ik raat het liever dan dat ik je vraag mij op mijn woord te geloven.

BevindingErnst
SeedSigner 0.8.7 controleert zijn camera nietLaag, de hoogste hier. Een afgedekte lens is een plausibel ongeluk. Opgelost in de volgende versie.
OneKey mist de entropiecontrole van TrezorLaag. Geen aanwijzing dat er iets mis is, maar je vertrouwt OneKey zonder enige controle die de bron ervan wel biedt.
Kruxs dobbelsteenbeoordeling is te misleidenLaag. Je zou je eigen worpen moeten vervalsen.
De JPEG-foto van SeedSignerInformatief. Kan een zaad niet verzwakken, want willekeur die er eenmaal in zit, kan er niet meer uit.
De vijf nullen van JadeInformatief. Nullen tellen niet op en trekken niets af.
Trezor controleert alleen weggegooide walletsInformatief. Bewust, en verdedigbaar. Alleen wordt het breed verkeerd omschreven.

Dat niets boven Laag uitkomt, is waarom ik meteen publiceer. Onderzoekers wachten normaal negentig dagen, om aanvallers op afstand te houden terwijl er een oplossing wordt gebouwd. Hier is geen aanval om achter te houden, geen oplossing waar iemand op wacht, en elke regel die ik citeer staat al in een openbare repository. Achterhouden zou reputaties beschermen, geen mensen. Ik stel elk project op de hoogte, en elke reactie wordt hier toegevoegd.

Ik heb ook BitBox02, Bitkey en Ledger gelezen. Bij BitBox02 en Bitkey was er niets te melden, en dat is het waard om hardop te zeggen. Bitkey faalt bovendien veilig: als zijn willekeurbron een fout geeft, stopt het apparaat in plaats van door te gaan. Ledger viel helemaal niet te beoordelen, omdat de code die het zaad aanmaakt nooit is gepubliceerd.

Eén ding om te melden: Bitsaga beveelt SeedSigner aan, schrijft erover en bouwde er een browsersimulator voor. Mijn scherpste bevinding gaat over SeedSigner, en daar ben ik mee begonnen, want een recensie die je eigen favoriet spaart, is geen recensie.

Gelezen op deze vaste versies: Keystone 6ab436a, OneKey e99ba63, Bitkey 4ba8c4c, SeedSigner fa35c35, Krux 8afa9ee, Coldcard e33ef92, Trezor dd7afbc, Jade 5ad8566, BitBox02 a3467ad.