COLDCARD RNG incident the public record, collected and explained
Informational only, and this site never asks for your seed words. details

Informational only. This is an open source collection of what others have published about the incident, together with an explanation of it. It is not financial, security or legal advice, and not a substitute for professional advice about your own situation. It is not affiliated with, endorsed by, or speaking for Coinkite. Material is attributed and quoted as published; where sources disagree their scenarios are kept separate with their assumptions rather than reconciled into one answer. Everything is meant to be checked against the linked evidence rather than taken on trust. Act on your own judgement about a particular situation. Editorial standards and corrections.

Do not disclose recovery material to a website, form, message or support account. This site never asks for it, and contributions containing recovery words or private keys are not accepted.

Dettmer commit-history analysis of the entropy bug

btcpp-dettmer-commit-history

https://insider.btcpp.dev/p/when-randombytes-runs-but-doesnt

Latest reviewed change

source content difference between and

A new comment from Boomberg appeared asserting the bad code came from the switck/libngu repository, and the comment total rose from 3 to 4. Engagement counters also moved.

seen +14 -13 full history below
 What a commit message tells us about the recent COLDCARD bug
 Dusty Daemon
 Aug 01, 2026
-25
-3
-3
+36
+4

First lines only. The complete diff is in the timeline below.

Organisation
bitcoin++ Insider Edition
Evidence role
Independent primary analysis
Published
2026-08-01
Source changes
3
Detected differences
14
Unreviewed
0
Copies held
15

Dustin Dettmer's walkthrough of the COLDCARD firmware commit history tracing how the predictable generator path was introduced. Published on the bitcoin++ Insider Edition substack; its commit-level claims are checkable against the pinned repository clones held by this archive.

Every check is recorded, including checks that found no text change. A detected edit is therefore bounded between two checks. The publisher's exact save time is not observable from this record. Last checked .

  1. source content difference between and source content +14 -13

    A new comment from Boomberg appeared asserting the bad code came from the switck/libngu repository, and the comment total rose from 3 to 4. Engagement counters also moved.

    seen · Captured here 9,986 chars
    What changed from the previous capture 27 lines
     What a commit message tells us about the recent COLDCARD bug
     Dusty Daemon
     Aug 01, 2026
    -25
    -3
    -3
    +36
    +4
    +4
     Share
     This is a guest post from noted Core-Lightning developer, ddustin, who dug into the Coldcard firmware commit history to uncover what happened and why the code failed.
     Intro
     I hope that we, as an industry, can learn from this and lean on each other to ship secure code, as a community of developers.
     Thanks for reading bitcoin++'s Insider Edition! Click below to share this post with your GC
     Share
    -25
    -3
    -3
    +36
    +4
    +4
     Share
     A guest post by
     Dusty Daemon
     Subscribe to Dusty
     Discussion about this post
     CommentsRestacks
    +Boomberg
    +4h
    +https://github.com/switck/libngu
    +is to blame. The bad code came from here
    +Reply
    +Share
     Curious George
    -5h
    +12h
     Very well said. As a retired dev I appreciate this analysis. Good God - how can you ship code you don't understand, especially involving money? People's lives are at risk!!
     Complexity **IS** the enemy.
     Reply
     Share
    -Lynne Bairstow
    -6h
    -Exceptional explanation—thanks, Dusty. I believe anyone impacted by this (and, aren’t we all?) wants to understand what the heck happened; how it could have possibly happened—and this unravels the mystery. Your closing remarks are the critical take-away.
    -Reply
    -Share
    -1 more comment...
    +2 more comments...
     TopLatestDiscussions
     No posts
     Ready for more?
    
    Extracted text as captured
    SubscribeSign in
    OpEd
    When random.bytes() runs but doesn't work
    What a commit message tells us about the recent COLDCARD bug
    Dusty Daemon
    Aug 01, 2026
    36
    4
    4
    Share
    This is a guest post from noted Core-Lightning developer, ddustin, who dug into the Coldcard firmware commit history to uncover what happened and why the code failed.
    Intro
    I began investigating the Coldcard hack and was immediately shocked. I need to explain why.
    When we developers work on code, we organize or code changes into changesets we call “commits.” The purpose of doing so is to show a clear history of what code was changed including why and how.
    This is done precisely for instances like this where it appears Bitcoiner’s funds are being stolen en masse, so we can investigate and understand exactly how it could happen.
    Good developers write clear commit messages, written notes that go along with the code changes that explain what the specific change is accomplishing.
    To make a clear commit message, you typically want to the commit to represent a smaller change of code, so there’s less to comment on.
    A good goal as a developer is a high commit message to change ratio. The more lines of code that you change, the more comments explaining why you’re changing the code. More message and less code changes per commit is generally a good idea.
    Here is an example chosen randomly from some of my own work.
    The commit message is 235 characters, and the commit changes 15 lines of code. That’s a ratio of 235/15 = ~16.
    In the cold card, the commit that introduced the low entropy bug is here.
    The commit message is 5 characters and is simply the word “runs.” The commit changes 1534 lines of code making the ratio 5/1534 = ~0.003
    This is an atrociously bad comment to code change ratio.
    There are some rare instances where a low comment ratio is justifiable -- but changing the most important part of the code is not one of those cases!
    Code that touches functions critical to the security of the project need to have a higher ratio of comments to changes and more stringent review.
    The second commit contributing to the weak entropy issue on Coldcards is here.
    The commit message is 1 character: simply the character “x.” The commit changes ~1000 lines of code making the ratio 1/1000 = ~0.001
    The Issue
    In the commit titled “runs” (ratio: ~0.003), it appears they are importing and configuring C code to make custom micropython code work on the STM32, the board that all Coldcards run on.
    STM32 is the most common CPU for small devices like this, and configurations like what this commit introduces are common.
    In the ‘runs’ commit, the hardware RNG (Random Number Generation) was disabled with the following line of code.
    #define MICROPY_HW_ENABLE_RNG (0)
    This is what caused the bug. Setting this value to zero tells the default micropython rng code to not use the hardware RNG device and that it should use the Yasmarang RNG instead.
    The developer added an inline comment “explaining” this change
    // We have our own version of this code.
    The COLDCARD version of this code appears to be in reference to the functions added in rng.h and rng.c
    rng.h
    MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj);
    MP_DECLARE_CONST_FUN_OBJ_1(pyb_rng_get_bytes_obj);
    These appear to be an attempt to override the stm32 rng library’s `pyb_rng_getobj` function. This approach ran into trouble. The stm32 rng.c file already defines the pyb_rng_et_obj variable and sets the value to `pyb_mg_get`. You can’t have two definitions of the same variable and have it compile.

    Excerpt only. The complete copy is held offline and backs quotations on this site. The original publication remains the canonical public source.

  2. source content difference between and source content +16 -9

    Two new reader comments appeared in the discussion section (Curious George and Lynne Bairstow, with a 1 more comment line). Like, comment and restack counters also moved.

    seen · Captured here 10,171 chars
    What changed from the previous capture 25 lines
     What a commit message tells us about the recent COLDCARD bug
     Dusty Daemon
     Aug 01, 2026
    -8
    -1
    -1
    +22
    +3
    +2
     Share
     This is a guest post from noted Core-Lightning developer, ddustin, who dug into the Coldcard firmware commit history to uncover what happened and why the code failed.
     Intro
     I hope that we, as an industry, can learn from this and lean on each other to ship secure code, as a community of developers.
     Thanks for reading bitcoin++'s Insider Edition! Click below to share this post with your GC
     Share
    -8
    -1
    -1
    +22
    +3
    +2
     Share
     A guest post by
     Dusty Daemon
     Subscribe to Dusty
     Discussion about this post
     CommentsRestacks
    -Frank Corva
    -34m
    -Great piece. Thank you, Rusty and Nifty.
    +Curious George
    +3h
    +Very well said. As a retired dev I appreciate this analysis. Good God - how can you ship code you don't understand, especially involving money? People's lives are at risk!!
    +Complexity **IS** the enemy.
     Reply
     Share
    +Lynne Bairstow
    +4h
    +Exceptional explanation—thanks, Dusty. I believe anyone impacted by this (and, aren’t we all?) wants to understand what the heck happened; how it could have possibly happened—and this unravels the mystery. Your closing remarks are the critical take-away.
    +Reply
    +Share
    +1 more comment...
     TopLatestDiscussions
     No posts
     Ready for more?
    
    Extracted text as captured
    SubscribeSign in
    OpEd
    When random.bytes() runs but doesn't work
    What a commit message tells us about the recent COLDCARD bug
    Dusty Daemon
    Aug 01, 2026
    22
    3
    2
    Share
    This is a guest post from noted Core-Lightning developer, ddustin, who dug into the Coldcard firmware commit history to uncover what happened and why the code failed.
    Intro
    I began investigating the Coldcard hack and was immediately shocked. I need to explain why.
    When we developers work on code, we organize or code changes into changesets we call “commits.” The purpose of doing so is to show a clear history of what code was changed including why and how.
    This is done precisely for instances like this where it appears Bitcoiner’s funds are being stolen en masse, so we can investigate and understand exactly how it could happen.
    Good developers write clear commit messages, written notes that go along with the code changes that explain what the specific change is accomplishing.
    To make a clear commit message, you typically want to the commit to represent a smaller change of code, so there’s less to comment on.
    A good goal as a developer is a high commit message to change ratio. The more lines of code that you change, the more comments explaining why you’re changing the code. More message and less code changes per commit is generally a good idea.
    Here is an example chosen randomly from some of my own work.
    The commit message is 235 characters, and the commit changes 15 lines of code. That’s a ratio of 235/15 = ~16.
    In the cold card, the commit that introduced the low entropy bug is here.
    The commit message is 5 characters and is simply the word “runs.” The commit changes 1534 lines of code making the ratio 5/1534 = ~0.003
    This is an atrociously bad comment to code change ratio.
    There are some rare instances where a low comment ratio is justifiable -- but changing the most important part of the code is not one of those cases!
    Code that touches functions critical to the security of the project need to have a higher ratio of comments to changes and more stringent review.
    The second commit contributing to the weak entropy issue on Coldcards is here.
    The commit message is 1 character: simply the character “x.” The commit changes ~1000 lines of code making the ratio 1/1000 = ~0.001
    The Issue
    In the commit titled “runs” (ratio: ~0.003), it appears they are importing and configuring C code to make custom micropython code work on the STM32, the board that all Coldcards run on.
    STM32 is the most common CPU for small devices like this, and configurations like what this commit introduces are common.
    In the ‘runs’ commit, the hardware RNG (Random Number Generation) was disabled with the following line of code.
    #define MICROPY_HW_ENABLE_RNG (0)
    This is what caused the bug. Setting this value to zero tells the default micropython rng code to not use the hardware RNG device and that it should use the Yasmarang RNG instead.
    The developer added an inline comment “explaining” this change
    // We have our own version of this code.
    The COLDCARD version of this code appears to be in reference to the functions added in rng.h and rng.c
    rng.h
    MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj);
    MP_DECLARE_CONST_FUN_OBJ_1(pyb_rng_get_bytes_obj);
    These appear to be an attempt to override the stm32 rng library’s `pyb_rng_getobj` function. This approach ran into trouble. The stm32 rng.c file already defines the pyb_rng_et_obj variable and sets the value to `pyb_mg_get`. You can’t have two definitions of the same variable and have it compile.

    Excerpt only. The complete copy is held offline and backs quotations on this site. The original publication remains the canonical public source.

  3. source content difference between and source content +9 -0

    A reader comment from Frank Corva was added to the post's discussion, posted after the preceding capture rather than progressively rendered from it. Substack like and restack counters changed in the same capture. The guest post's own text was unchanged.

    seen · Captured here 9,703 chars
    What changed from the previous capture 9 lines
     What a commit message tells us about the recent COLDCARD bug
     Dusty Daemon
     Aug 01, 2026
    +8
    +1
     1
     Share
     This is a guest post from noted Core-Lightning developer, ddustin, who dug into the Coldcard firmware commit history to uncover what happened and why the code failed.
     I hope that we, as an industry, can learn from this and lean on each other to ship secure code, as a community of developers.
     Thanks for reading bitcoin++'s Insider Edition! Click below to share this post with your GC
     Share
    +8
    +1
     1
     Share
     A guest post by
     Subscribe to Dusty
     Discussion about this post
     CommentsRestacks
    +Frank Corva
    +34m
    +Great piece. Thank you, Rusty and Nifty.
    +Reply
    +Share
     TopLatestDiscussions
     No posts
     Ready for more?
    
    Extracted text as captured
    SubscribeSign in
    OpEd
    When random.bytes() runs but doesn't work
    What a commit message tells us about the recent COLDCARD bug
    Dusty Daemon
    Aug 01, 2026
    8
    1
    1
    Share
    This is a guest post from noted Core-Lightning developer, ddustin, who dug into the Coldcard firmware commit history to uncover what happened and why the code failed.
    Intro
    I began investigating the Coldcard hack and was immediately shocked. I need to explain why.
    When we developers work on code, we organize or code changes into changesets we call “commits.” The purpose of doing so is to show a clear history of what code was changed including why and how.
    This is done precisely for instances like this where it appears Bitcoiner’s funds are being stolen en masse, so we can investigate and understand exactly how it could happen.
    Good developers write clear commit messages, written notes that go along with the code changes that explain what the specific change is accomplishing.
    To make a clear commit message, you typically want to the commit to represent a smaller change of code, so there’s less to comment on.
    A good goal as a developer is a high commit message to change ratio. The more lines of code that you change, the more comments explaining why you’re changing the code. More message and less code changes per commit is generally a good idea.
    Here is an example chosen randomly from some of my own work.
    The commit message is 235 characters, and the commit changes 15 lines of code. That’s a ratio of 235/15 = ~16.
    In the cold card, the commit that introduced the low entropy bug is here.
    The commit message is 5 characters and is simply the word “runs.” The commit changes 1534 lines of code making the ratio 5/1534 = ~0.003
    This is an atrociously bad comment to code change ratio.
    There are some rare instances where a low comment ratio is justifiable -- but changing the most important part of the code is not one of those cases!
    Code that touches functions critical to the security of the project need to have a higher ratio of comments to changes and more stringent review.
    The second commit contributing to the weak entropy issue on Coldcards is here.
    The commit message is 1 character: simply the character “x.” The commit changes ~1000 lines of code making the ratio 1/1000 = ~0.001
    The Issue
    In the commit titled “runs” (ratio: ~0.003), it appears they are importing and configuring C code to make custom micropython code work on the STM32, the board that all Coldcards run on.
    STM32 is the most common CPU for small devices like this, and configurations like what this commit introduces are common.
    In the ‘runs’ commit, the hardware RNG (Random Number Generation) was disabled with the following line of code.
    #define MICROPY_HW_ENABLE_RNG (0)
    This is what caused the bug. Setting this value to zero tells the default micropython rng code to not use the hardware RNG device and that it should use the Yasmarang RNG instead.
    The developer added an inline comment “explaining” this change
    // We have our own version of this code.
    The COLDCARD version of this code appears to be in reference to the functions added in rng.h and rng.c
    rng.h
    MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj);
    MP_DECLARE_CONST_FUN_OBJ_1(pyb_rng_get_bytes_obj);
    These appear to be an attempt to override the stm32 rng library’s `pyb_rng_getobj` function. This approach ran into trouble. The stm32 rng.c file already defines the pyb_rng_et_obj variable and sets the value to `pyb_mg_get`. You can’t have two definitions of the same variable and have it compile.

    Excerpt only. The complete copy is held offline and backs quotations on this site. The original publication remains the canonical public source.

  4. Earliest copy held
    seen · Captured here 9,626 chars
    Extracted text as captured
    SubscribeSign in
    OpEd
    When random.bytes() runs but doesn't work
    What a commit message tells us about the recent COLDCARD bug
    Dusty Daemon
    Aug 01, 2026
    1
    Share
    This is a guest post from noted Core-Lightning developer, ddustin, who dug into the Coldcard firmware commit history to uncover what happened and why the code failed.
    Intro
    I began investigating the Coldcard hack and was immediately shocked. I need to explain why.
    When we developers work on code, we organize or code changes into changesets we call “commits.” The purpose of doing so is to show a clear history of what code was changed including why and how.
    This is done precisely for instances like this where it appears Bitcoiner’s funds are being stolen en masse, so we can investigate and understand exactly how it could happen.
    Good developers write clear commit messages, written notes that go along with the code changes that explain what the specific change is accomplishing.
    To make a clear commit message, you typically want to the commit to represent a smaller change of code, so there’s less to comment on.
    A good goal as a developer is a high commit message to change ratio. The more lines of code that you change, the more comments explaining why you’re changing the code. More message and less code changes per commit is generally a good idea.
    Here is an example chosen randomly from some of my own work.
    The commit message is 235 characters, and the commit changes 15 lines of code. That’s a ratio of 235/15 = ~16.
    In the cold card, the commit that introduced the low entropy bug is here.
    The commit message is 5 characters and is simply the word “runs.” The commit changes 1534 lines of code making the ratio 5/1534 = ~0.003
    This is an atrociously bad comment to code change ratio.
    There are some rare instances where a low comment ratio is justifiable -- but changing the most important part of the code is not one of those cases!
    Code that touches functions critical to the security of the project need to have a higher ratio of comments to changes and more stringent review.
    The second commit contributing to the weak entropy issue on Coldcards is here.
    The commit message is 1 character: simply the character “x.” The commit changes ~1000 lines of code making the ratio 1/1000 = ~0.001
    The Issue
    In the commit titled “runs” (ratio: ~0.003), it appears they are importing and configuring C code to make custom micropython code work on the STM32, the board that all Coldcards run on.
    STM32 is the most common CPU for small devices like this, and configurations like what this commit introduces are common.
    In the ‘runs’ commit, the hardware RNG (Random Number Generation) was disabled with the following line of code.
    #define MICROPY_HW_ENABLE_RNG (0)
    This is what caused the bug. Setting this value to zero tells the default micropython rng code to not use the hardware RNG device and that it should use the Yasmarang RNG instead.
    The developer added an inline comment “explaining” this change
    // We have our own version of this code.
    The COLDCARD version of this code appears to be in reference to the functions added in rng.h and rng.c
    rng.h
    MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj);
    MP_DECLARE_CONST_FUN_OBJ_1(pyb_rng_get_bytes_obj);
    These appear to be an attempt to override the stm32 rng library’s `pyb_rng_getobj` function. This approach ran into trouble. The stm32 rng.c file already defines the pyb_rng_et_obj variable and sets the value to `pyb_mg_get`. You can’t have two definitions of the same variable and have it compile.
    rng.c
    MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get);

    Excerpt only. The complete copy is held offline and backs quotations on this site. The original publication remains the canonical public source.

11 presentation-noise differences. Sidebar, ticker and other page chrome churn that our review classified as not being changes to what the source says.
  • +1 -1 Only a relative comment-age label changed from a placeholder to 'Aug 2'; the article text and discussion comments were unchanged.
  • +1 -1 Only a relative comment-age label changed from a tag to 'Aug 1'; the article text and discussion were unchanged.
  • +7 -5 The embedded discussion widget showed a different subset of existing comments; the article text did not change.
  • +5 -7 The rendered comment preview rotated among existing comments and like metadata.
  • +7 -5 The rendered comment preview rotated among existing comments and like metadata.
  • +5 -5 Only the rendered comment order changed. The article text and comments were otherwise unchanged.
  • +5 -5 Only the rendered comment order changed. The article text and comments were otherwise unchanged.
  • +5 -5 Substack reordered the comment display: the same Lynne Bairstow and Curious George comments swapped positions with no text added, removed or altered.
  • +6 -6 Only Substack engagement counters (46 to 54 likes, 6 to 10 restacks) and comment age stamps rolling from hours to 1d changed.
  • +11 -12 Rotating comment display: the comment total stayed at 4 while the page swapped which two comments are shown, and only counters and relative ages otherwise changed.
  • +6 -6 Only Substack engagement counters (22 to 25 likes, 2 to 3 restacks) and relative comment age stamps (3h to 5h, 4h to 6h) changed.
How to check this yourself

The excerpts and plain unified diffs above show the text this project held and how it changed. To verify a quotation, compare it against the page itself or against the Internet Archive's copies, which are independent of this project.

Complete captures are held offline rather than mirrored here, so this page shows diffs and excerpts. If a quotation is ever disputed, the full copy can be produced. Ask.