Back to Blog

COLDCARD-Vorfall: Als der „zufällige" Seed einer Wallet nicht zufällig war

Code Auditing
August 7, 2026
15 min read
Key Insights
  • COLDCARDs Verluste gehen auf einen einzelnen Build-Konfigurationsfehler zurück – ein Makro-Guard prüfte die Existenz (#ifndef) statt den Wert (#if) und leitete die Seed-Generierung stillschweigend an einen deterministischen Software-RNG-Fallback weiter.

  • Der Angriff war vollständig offline: keine On-Chain-Exploit-Transaktion, nur Seed-Enumeration (~40 Bit bei Mk2/Mk3, ~72 Bit bei Mk4/Q/Mk5), abgeglichen mit öffentlichen Wallet-Daten.

  • Ein Firmware-Update behebt bereits generierte Seeds nicht – kompromittierte Gelder müssen auf einen neuen Seed übertragen werden, der mit einer gepatchten Version erstellt wurde.

  • Der Fall zeigt, warum kryptografische Entropiepfade ausfallsicher sein und in der ausgelieferten Firmware durchgängig verifiziert werden müssen – nicht nur zur Kompilierzeit.

Kurzzusammenfassung

Ab dem 30. Juli 2026 wurden in mehreren Wellen Gelder aus COLDCARD Bitcoin Hardware-Wallets abgezogen, wobei sich die Vorgänge in den folgenden Tagen fortsetzten. Es gab keine einzelne On-Chain-Angriffstransaktion und keinen angreifbaren Vertrag; der Verlust entstand durch ein Offline-Seed-Wiederherstellungsproblem, gefolgt von On-Chain-Überweisungen. Stand 7. August 2026 hatte das On-Chain-Tracking eine Untergrenze von etwa 1.405 BTC (~$91M zum $64.700-Preis vom 7. August) bestätigt, die aus rund 4.925 Adressen abgezogen wurden [1], die wellenweise Zuordnung ergab etwa 1.433 BTC über zehn Wellen [2], und die Abstimmung über private Kanäle mit Opfern bezifferte den Betrag auf bis zu 2.055 BTC (~$133M) [3].

Die eigentliche Ursache war ein Wallet-Entropiefehler: Eine Firmware-Migration aus dem Jahr 2021 leitete die Seed-Generierung über ngu.random.bytes(), das auf einen deterministischen Software-Generator zurückfiel, anstatt den vorgesehenen STM32 Hardware-RNG zu verwenden. Für betroffene Geräte reduzierte dies die Seed-Wiederherstellung von einem kryptografisch unlösbaren Problem auf eine Offline-Suche, sodass ein Angreifer Kandidaten-Seeds aufzählen und mit öffentlichen Wallet-Daten abgleichen konnte, um die privaten Schlüssel wiederherzustellen. Aufbauend auf unserer früheren wöchentlichen Analyse des Vorfalls quantifiziert diese Tiefenanalyse die verbleibende Entropie für jede betroffene Gerätegeneration, verfolgt, wie Opfer und gestohlene Gelder On-Chain identifiziert wurden, und untersucht eine separate Firmware-Regression nach dem Hotfix, die vor der Anmeldung einen Denial-of-Service verursachen kann.

Hintergrund

COLDCARD ist eine Bitcoin Hardware-Wallet. Wie bei anderen Self-Custody-Wallets hängt die Sicherheit letztlich von der Unvorhersehbarkeit der beim Wallet-Setup generierten Seed-Phrase ab. Eine BIP-39-Seed-Phrase ist für Menschen lesbar, aber die zugrunde liegende Sicherheitseigenschaft ist dennoch die Entropie der zur Erstellung verwendeten Zufallsbytes. Wenn die Ausgabe der Seed-Generierung vorhersehbar ist, bricht die Sicherheit der Wallet zusammen, egal wie sorgfältig der Seed danach aufbewahrt wird.

COLDCARD umfasst die Hardware-Revisionen Mk1 bis Mk5 sowie das Q-Modell. Mk2 und Mk3 verwenden die Legacy-Firmware-Linie. Mk4, Mk5 und Q verwenden separate Standard- und Edge-Release-Tracks.

Der Großteil der COLDCARD-Anwendungslogik ist in Python implementiert und läuft auf MicroPython, wobei native C-Module Hardware- und kryptografische Operationen bereitstellen. Ein sicherer Seed-Generierungspfad sollte 32 Bytes vom STM32 Hardware-RNG lesen, fehlschlagen, wenn das Peripheral stoppt oder einen Wert wiederholt, das Ergebnis hashen und es dann als BIP-39-Wörter kodieren. In v3.2.2 folgte make_new_wallet() diesem Pfad:

make_new_wallet()
  |- ckcc.rng_bytes(seed)
  |    `- random_buffer()
  |         |- read STM32 RNG->DR
  |         `- fail on timeout or repeated output
  |- SHA-256(seed)
  `- BIP-39 seed words

Schwachstellenanalyse

Die Grundursache war ein Build- und Integrationsfehler rund um MICROPY_HW_ENABLE_RNG. Die Produktionsboard-Konfiguration von COLDCARD setzte dieses Makro auf 0, da die Firmware ihren eigenen board-lokalen Hardware-RNG-Wrapper verwendete statt der Hardware-RNG-Implementierung von MicroPython. Jedoch war der Wallet-Generierungspfad zu ngu.random.bytes(32) migriert worden, und libngu's STM32-Pfad hing letztlich vom globalen Symbol rng_get() ab.

Der betroffene Pfad gelangte in libngu's my_random_bytes(). Für jedes Ausgabewort verknüpfte es den von CHIP_TRNG_32() zurückgegebenen Wert mit seiner eigenen Yasmarang-Ausgabe per XOR:

generate_seed()
  `- ngu.random.bytes(32)
       `- my_random_bytes()                [libngu]
            |- CHIP_TRNG_32()
            |    `- rng_get()              [MicroPython]
            |         `- Yasmarang A
            |              `- UID + SysTick + RTC
            |
            |- my_yasmarang()              [libngu]
            |    `- Yasmarang B
            |         |- Mk2/Mk3: öffentlicher Anfangszustand
            |         `- Mk4/Q/Mk5: 32-Bit-Pad-Reseed
            |
            `- Ausgabe = Yasmarang A XOR Yasmarang B

Yasmarang A war MicroPythons Fallback hinter rng_get(), initialisiert aus Geräte- und Timer-Zustand. Yasmarang B gehörte zu libngu: Es verwendete öffentliche Anfangswerte auf Mk2/Mk3, während Mk4/Q/Mk5 nur sein 32-Bit-pad mit Secure-Element-Daten ersetzte. Der board-lokale STM32 RNG existierte noch, aber ngu.random.bytes() rief ihn nicht auf.

Der Konflikt ist direkt in der Build-Konfiguration sichtbar. Die Mk4-mpconfigboard.h deaktivierte den Hardware-RNG-Zweig von MicroPython:

// We have our own version of this code.
#define MICROPY_HW_ENABLE_RNG (0)

Libngu's CHIP_TRNG_32() behandelte das Makro weiterhin als ausreichenden Beweis für einen Hardware-RNG, da es nur prüfte, ob das Makro existierte, und dann rng_get() aufrief:

extern uint32_t rng_get(void);
#define CHIP_TRNG_32() rng_get()

#ifndef MICROPY_HW_ENABLE_RNG
#error "get a HW TRNG plz"
#endif

Diese Absicherung übersieht den gefährlichen Fall: Ein Makro, das als 0 definiert ist, ist trotzdem definiert. Der Build war daher erfolgreich, und rng_get() wurde zum STM32 RNG-Modul von MicroPython aufgelöst, anstatt zu COLDCARDs separatem board-lokalen Wrapper (random32() / random_buffer(), in Python als ckcc.rng_bytes exponiert). In MicroPythons rng_get()-Auswahl wählte MICROPY_HW_ENABLE_RNG == 0 den Software-Fallback-Zweig:

#if MICROPY_HW_ENABLE_RNG
    // STM32 hardware RNG
#else
    // Yasmarang software fallback
#endif

Mk2/Mk3: Etwa 40 Bit

Der kompilierte pyb_rng_yasmarang()-Fallback initialisierte und aktualisierte Yasmarang wie folgt:

STATIC uint32_t pyb_rng_yasmarang(void) {
    static bool seeded = false;
    static uint32_t pad = 0, n = 0, d = 0;
    static uint8_t dat = 0;

    if (!seeded) {
        seeded = true;
        rtc_init_finalise();
        pad = *(uint32_t *)MP_HAL_UNIQUE_ID_ADDRESS ^ SysTick->VAL;
        n = RTC->TR;
        d = RTC->SSR;
    }

    pad += dat + d * n;
    pad = (pad << 3) + (pad >> 29);
    n = pad | 2;
    d ^= (pad << 31) + (pad >> 1);
    dat ^= (char)pad ^ (d >> 8) ^ 1;

    return pad ^ (d << 5) ^ (pad >> 18) ^ (dat << 1);
}

Die Variablen belegen 104 Bit, aber Zustandsgröße ist nicht Entropie. dat beginnt bei null, und die anderen Werte sind feste Metadaten oder korrelierte Timer-Lesungen statt unabhängiger Geheimnisse. Unter dem lockeren Mk2/Mk3-Modell, das für die ungefähre 40-Bit-Zahl verwendet wurde:

Eingabe Kandidatenwerte Aufzählungskosten
Bekanntes UID_low32 1 2^0
SysTick->VAL 80.000 2^16,29
RTC->TR Tageszeit 86.400 2^16,40
RTC->SSR Subsekunde 256 2^8

Die Behandlung aller Timer-Felder als unabhängig ergibt eine bewusst breite Obergrenze:

80.000 * 86.400 * 256
= 1.769.472.000.000
= 2^40,69 Kandidaten-Anfangszustände

Eine erschöpfende Suche erfordert daher höchstens 2^40,69 Versuche und unter einer Gleichverteilungsannahme durchschnittlich etwa 2^39,69 Versuche. Dies ist eine Aufzählungsobergrenze, keine 40 Bit kryptografische Entropie. Wenn die RTC-Register während eines normalen Kaltstarts statisch sind, verbleibt nur SysTick, was die Obergrenze auf etwa 2^16,29 reduziert. Wenn UID, Timer und die Anzahl früherer RNG-Aufrufe bekannt sind, gibt es genau einen Stream: 2^0. Unbekannte Aufrufhistorie fügt nur die Anzahl plausible Ausführungspfade hinzu, keine neue Entropiequelle. Ebenso multipliziert das Generieren von acht 32-Bit-Wörtern für einen 256-Bit-Seed den Suchraum nicht: Jedes Wort wird durch denselben Anfangszustand bestimmt.

Auf der libngu-Ebene mischte my_random_bytes() den obigen MicroPython-Fallback mit libngu's separatem Yasmarang-Generator. Der Quellcode enthält nicht wörtlich chip = rng_get(): CHIP_TRNG_32() expandiert zu rng_get(). Auf Mk2/Mk3 begann der zweite Generator mit öffentlichen Konstanten:

static uint32_t yasmarang_pad = 0x0a8ce26f, yasmarang_n = 69, yasmarang_d = 233;
static uint8_t yasmarang_dat = 0;

uint32_t chip = CHIP_TRNG_32();
// ... adjacent-output health check ...
chip ^= my_yasmarang();

Beide Streams waren daher reproduzierbar, sobald der MicroPython-Fallback-Zustand und die Aufrufhistorie bekannt waren. XOR änderte die Ausgabewerte, fügte aber keine Entropie hinzu. Selbst wenn UID_low32 unbekannt ist, kollabiert UID_low32 ^ SysTick beide Eingaben in ein 32-Bit-pad; ihre nominellen Bit-Anzahlen können nicht addiert werden.

Mk4/Q/Mk5: Etwa 72 Bit

Spätere Modelle behielten dieselbe Zwei-Generator-Konstruktion bei, aber rng_seeding() fügte dem Generator von libngu beim Boot Secure-Element-Material hinzu:

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)

Obwohl 40 Bytes in den Hash eingingen, erreichten nur die ersten vier Bytes reseed() [4]. Die random_reseed()-Implementierung ersetzte dann nur das 32-Bit-pad-Wort von libngu:

STATIC mp_obj_t random_reseed(mp_obj_t arg)
{
    yasmarang_pad = mp_obj_get_int_truncated(arg);
    return mp_const_none;
}

Die anderen libngu-Zustandswörter behielten ihre öffentlichen Werte, und der MicroPython-Fallback wurde nicht neu geseedet. Die ungefähre 72-Bit-Zahl kombiniert den 32-Bit-libngu-Reseed mit einer lockeren Obergrenze für den Timer-Zustand der späteren Modelle:

MicroPython-Fallback:
    120.000 SysTick-Werte * 86.400 RTC-Zeiten * 256 Subsekunden
    = 2^41,27 Zustände

Libngu sicherer Reseed:
    2^32 Werte

Kombinierte Obergrenze:
    2^41,27 * 2^32 = 2^73,27 Kandidaten

Durchschnittliche Aufzählung:
    2^73,27 / 2 = 2^72,27 Versuche

Dies ist die Quelle der „etwa 72 Bit"-Zahl. Es handelt sich um eine durchschnittliche Angriffs-Arbeitsschätzung, nicht um 72 Bit, die von den Secure Elements bereitgestellt werden. Die Timer-Felder sind korreliert und können rekonstruiert werden; wenn der MicroPython-Fallback-Zustand bekannt ist, verbleiben nur die 2^32 Reseed-Werte, was durchschnittlich 2^31 Versuche ergibt. Das Hashen der finalen 32 Zufallsbytes kann die Anzahl möglicher Seeds nicht erhöhen.

Betroffene Versionen

Gerät und Track Außerhalb dieser Regression Betroffene Seed-generierende Firmware Effektive Bit-Sicherheit Erste korrigierte Version
Mk1 Bis v3.0.6 Keine - N/A
Mk2/Mk3 Bis v3.2.2 v4.0.0–v4.1.9 (offizieller Hinweis ab v4.0.1) Etwa 40 Bit bei Betroffenheit v4.2.0
Mk4/Mk5 Standard N/A Vor v5.6.0 Etwa 72 Bit vor Fix; mindestens 128 Bit danach v5.6.0
Q Standard N/A Vor v1.5.0Q Etwa 72 Bit vor Fix; mindestens 128 Bit danach v1.5.0Q
Mk4/Mk5 Edge N/A Vor v6.6.0X Etwa 72 Bit vor Fix; mindestens 128 Bit danach v6.6.0X
Q Edge N/A Vor v6.6.0QX Etwa 72 Bit vor Fix; mindestens 128 Bit danach v6.6.0QX

Die relevante Version ist die Firmware, die den Seed generiert hat, nicht die aktuell installierte Firmware. Neue Seeds, die ab den korrigierten Versionen generiert werden, verwenden den korrigierten Pfad, aber ein Update repariert keinen bereits vorhandenen Seed nicht. Der offizielle betroffene Bereich für Mk2/Mk3 beginnt bei v4.0.1 [5], während die Quellcode-Analyse auch v4.0.0 einschließt [4]. Unabhängige Würfel-Entropie kann die Sicherheit des Seeds erhöhen, während eine starke BIP-39-Passphrase eine separate Barriere hinzufügt, ohne den Seed selbst zu reparieren [6].

Best Security Auditor for Web3

Validate design, code, and business logic before launch

Opfer- und Fondsverfolgung

Es gab keine On-Chain-Exploit-Transaktion zu verfolgen; die Wiederherstellung erfolgte notwendigerweise offline. Mit einem Seed, der durch betroffene Firmware generiert wurde, könnte ein Angreifer die oben beschriebenen Kandidaten-RNG-Zustände eingrenzen und aufzählen, den Seed-Generierungsstream jedes Kandidaten wiedergeben, die resultierenden Wallet-Schlüssel ableiten und sie mit öffentlichen Wallet-Daten abgleichen, um dann jede übereinstimmende finanzierte Wallet On-Chain zu leeren. Dies erreichte nur Wallets, die allein vom Seed ableitbar waren: Eine starke, einzigartige BIP-39-Passphrase mischt unabhängige, vom Benutzer bereitgestellte Entropie, die der RNG-Fehler nie berührt hat, über PBKDF2 in die Schlüsselableitung ein, wodurch solche Wallets außerhalb der reinen Seed-Aufzählung liegen. Die geleerten Wallets waren notwendigerweise solche ohne einen solchen Schutz [6]. Da der Diebstahl nur als On-Chain-Sweeps und nicht als verfolgbarer Exploit auftauchte, wurde die Identifizierung der Opfer und die Verfolgung der Gelder zu einer Frage der On-Chain-Forensik.

Mehrere unabhängige Bemühungen verfolgten die gestohlenen Gelder: öffentliche Tracking-Seiten (Coldcard Sweep Watch [1], coldcard.rip [2] und der Coldcard Hack Tracker [7]) sowie eine private Kanalabstimmung von Galaxy Research [3], wobei ihre gemeldeten Gesamtsummen unten verglichen werden. Da Coldcard Sweep Watch seine Methodik veröffentlichte, verwenden wir sie zur Veranschaulichung des Identifikationsprozesses, eine Rückkopplungsschleife zwischen Off-Chain-Berichten und On-Chain-Analyse:

  1. Off-Chain-Anker. Opfer und Forscher lieferten öffentliche Adressen oder Transaktions-IDs sowie Geräte- und Seed-Generierungskontext, soweit verfügbar. Jeder Bericht wurde als Hinweis behandelt und On-Chain überprüft; keine Seed-Phrase, kein privater Schlüssel oder xpub war erforderlich.
  2. On-Chain-Erweiterung. Ausgehend von bestätigten Ankern durchsuchten Scanner relevante Blöcke nach denselben Sweep-Merkmalen: ohne Wechselgeld geleerte Wallets, ähnliche Input-Typen, enges Timing, wiederholte Gebührensätze, gemeinsame Ziele oder spätere gemeinsame Ausgaben.
  3. Off-Chain-Gegenprüfungen. Neue Opferberichte, Forscher-Datensätze und Service-Zuordnungen wurden verwendet, um Kandidatenwellen zu bestätigen oder abzulehnen. Verifizierte Cluster und heuristische Kandidaten blieben getrennt.

Bitcoin identifiziert Adressen, nicht Personen oder Wallet-Modelle. Eine Wallet kann viele Adressen kontrollieren, daher ist die Adressanzahl nicht gleich der Opferanzahl. Die erste weit berichtete große Welle, 960188, umfasste 594,48 BTC; fortgesetzte Suche und Berichterstattung erhöhten die Gesamtsumme. Stand 7. August 2026 meldete Coldcard Sweep Watch eine verifizierte Untergrenze von etwa 1.405,07 BTC (~$91M zum $64.700-Preis vom 7. August) aus rund 4.925 Adressen [1], während der coldcard.rip-Snapshot vom 3. August bis zu 1.433,13 BTC brutto, 1.432,48 BTC an Ziele nach Gebühren, aus 5.477 Adressen über zehn Wellen zuordnete [2]. Eine separate private Kanalabstimmung von Galaxy Research, basierend auf Korrespondenz mit Opfern, bezifferte den Betrag noch höher, von etwa 1.596 BTC bis zu 2.055 BTC (~$133M zum selben Preis) [3]. Die Unterschiede spiegeln Beweisschwellen, Entdeckungszeit und den Bestätigungskanal wider, auf den sich jeder Tracker stützt.

Die Gelder wurden dann durch drei beobachtete Schichten verfolgt: geleerte Quelladressen, direkte Sweep-Ziele (holding) und nachfolgende Konsolidierungsziele (vault). Die Tabelle zeigt die Anzahl der eindeutigen Adressen auf jeder Ebene:

Muster Beispielrouten Tracking-Konsequenz
Viele Sweeps zu einer oder zwei Holding-Adressen, dann ein Vault 960183: 204 -> 2 -> 1; 960188: 500 -> 1 -> 1 Zielkonvergenz macht den Cluster vergleichsweise stark und leicht zu verfolgen
Sweeps enden bei Holding-Adressen ohne nachfolgende Konsolidierung 960352: 352 -> 1 -> 0; 960668: 795 -> 1 -> 0 Die Holding-Adresse bleibt verfolgbar, aber es gibt keine spätere gemeinsame Ausgabe zur Stärkung der Zuordnung
Neue Ziele pro Sweep, manchmal gefolgt von separaten Vaults 960359: 13 -> 13 -> 0; 960395: 1.918 -> 294 -> 293 Ein gemeinsamer Kollektor-Detektor versagt; die Gruppierung hängt von Timing, Gebührensatz, Transaktionsvorlage und Off-Chain-Bestätigung ab

Wenn verfolgte Ausgaben sich bewegen, folgt die Analyse Splits, Zusammenführungen und Peel Chains, wobei der Wert nach Gebühren erhalten und die Zuordnung auf den geleerten Betrag begrenzt wird. Gelder, die in eine Börse oder einen anderen gemeinsamen Dienst fließen, reduzieren die Konfidenz; der Dienst wird nicht zum Angreifer-Cluster hinzugefügt.

Explore MetaSleuth Investigation

Trace flows and build evidence for investigations

Try now for free

Ein Fix, der einen Fix brauchte: Eine potenzielle Brick-Regression?

Getrennt vom Entropiefehler führte der Hotfix, der ihn behob, eine separate Firmware-Regression ein [8, 9]. Bei der Wiederherstellung des Hardware-RNG-Pfads ließ der Fix einen Hardware-Seed-Fehlerzustand unbehandelt, der vor der Anmeldung den Dienst verweigern kann und Behauptungen über dauerhaft gemauerte Geräte auslöste. Wie weit diese stärkere Behauptung zutrifft, hängt von den Register-Level-Details ab.

Der STM32 Hardware-RNG stellt ein Kontrollregister (RNG_CR), ein Statusregister (RNG_SR) und ein 32-Bit-Datenregister (RNG_DR) bereit. Der relevante Status ist:

Bit Rolle
RNGEN Aktiviert den RNG und seine analogen Rauschquellen
DRDY Zeigt an, dass Daten in RNG_DR bereit sind; Software muss trotzdem Null ablehnen
SECS / SEIS Aktueller Seed-Gesundheitstest-Fehler / gespeicherter Seed-Fehlerstatus
CECS / CEIS Aktueller RNG-Taktfehler / gespeicherter Taktfehlerstatus

Die Unterscheidung zwischen aktuellem und gespeichertem Status ist wichtig. SECS beschreibt den aktuellen Zustand der Rauschquelle, während SEIS aufzeichnet, dass ein Seed-Fehler aufgetreten ist, bis die Software ihn löscht. Auf dem Mk4/Q-Familie STM32L4S stoppt ein Seed-Fehler die neue Zufallszahlengenerierung; auf dem Mk3 STM32L4 können Daten verfügbar bleiben, dürfen aber nicht vertraut werden. Taktfehler sind getrennt und verursachen keine Seed-Fehler-Sperre.

Die erforderliche Wiederherstellungssequenz hängt von der STM32-Generation ab:

Gerätefamilie Dokumentierte Seed-Fehler-Wiederherstellung
Mk3 STM32L4 (RM0351, RNG-Fehlermanagement [10]) SEIS löschen, dann RNGEN löschen und setzen
Mk4/Q-Familie STM32L4S (RM0432, RNG-Fehlermanagement [11]) SEIS löschen, 12 RNG_DR-Wörter lesen und verwerfen, dann bestätigen, dass SEIS gelöscht bleibt

Der Entropie-Hotfix vom 31. Juli sorgte korrekt dafür, dass rng_get() zum Hardware-TRNG aufgelöst wird, aber die rng_get_or_fault() der Mk4/Q-Familie implementiert keine Seed-Fehler-Wiederherstellung. rng_init() agiert nur, wenn RNGEN gelöscht ist, während die Leseschleife nur DRDY prüft. Wenn ein Seed-Fehler RNGEN aktiviert lässt, aber DRDY unterdrückt, wird die Initialisierung zu einem No-Op; jeder Lesevorgang wartet 10 ms und wirft OSError(EFAULT), ohne SEIS zu löschen.

Dies kann die Benutzeroberfläche vor der Anmeldung erreichen. Sowohl das Tastenfeld mempad._start_scan() als auch das Q-keyboard._start_scan() mischen ihre Scan-Reihenfolge aus dem Tastendruck-Interrupt. Eine RNG-Ausnahme dort kann die PIN-Eingabe und das normale Firmware-Upgrade-Menü für den Rest dieser Hardware-Sitzung blockieren.

Der Fehler auf Code-Ebene ist glaubwürdig, aber die stärkere Behauptung eines „dauerhaften Brick-Angriffs" ist nicht belegt. Die RNG-Steuerungs- und Statusbits werden bei einem Hardware-Reset auf null zurückgesetzt, daher sollte ein einzelner transienter Fehler das Peripheral nicht dauerhaft beschädigen; Persistenz über einen vollständigen Stromzyklus hinaus wurde nicht nachgewiesen. Ebenso gibt es keine nachgewiesene ferngesteuerte oder zuverlässig kontrollierte Methode, den Seed-Gesundheitstest-Fehler auszulösen. Ein X-Post [8] bezeichnete das Bricking als bestätigt, aber der PR, auf den er verwies, der community-eingereichte PR #692 [9], enthält die Aussage des eigenen Autors, dass er den Fehler mit einem Register-Mock analysierte, ihn auf echter Mk4/Q-Hardware nicht reproduzierte und die Feldberichte nicht unabhängig bestätigte. Die am besten gestützte Klassifizierung ist daher eine potenzielle Pre-Login-Denial-of-Service- und Zuverlässigkeitsregression, kein bestätigter dauerhafter Brick-Angriff.

Der eigene Fix der Maintainer, PR #693 [12], prüft die Seed-Fehler-Flags, fügt begrenzte Wiederherstellung und Wiederholungsversuche hinzu, lehnt verdächtige Proben ab und fängt nur den erwarteten Tastenfeld-Fehler ab; er wurde am 5. August 2026 zusammengeführt und ersetzte den Community-PR #692 [9], der am 4. August 2026 ungemergt geschlossen wurde.

Fazit

Dieser Vorfall war ein Wallet-Entropiefehler, der die Seed-Wiederherstellung für betroffene Geräte und Workflows von kryptografisch unlösbar in ein Offline-Suchproblem verwandelte. Der zentrale technische Fehler war, dass die ausgelieferte Firmware nicht nachweisen konnte, dass die sicherheitskritische Seed-Generierungs-API tatsächlich den vorgesehenen Hardware-RNG erreichte. Build-Absicherungen müssen sowohl das Vorhandensein als auch den Wert des Makros prüfen, Fallbacks für kryptografische Entropie müssen im Fehlerfall geschlossen sein, und CI sollte Symbol-Provenienz und End-to-End-Entropiefluss im finalen Firmware-Image verifizieren. Für betroffene Benutzer ist die Abhilfe kein Firmware-Update: Ein Update repariert keinen Seed, der bereits unter dem fehlerhaften Pfad generiert wurde, und das nachträgliche Hinzufügen einer Passphrase schützt keine Gelder, die bereits an den Adressen dieses Seeds gehalten werden. Diese Gelder müssen in eine Wallet verschoben werden, die aus einem neuen Seed auf einer korrigierten Version aufgebaut ist; nur Gelder, die bereits hinter einer starken, einzigartigen Passphrase lagen, blieben außerhalb der reinen Seed-Aufzählung [6].

Referenzen

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit