COLDCARD 엔트로피 결함: 조용한 RNG 폴백은 어떻게 사용자에게 3,800만 달러의 손실을 안겼나

AbbieAbbie
/최종 업데이트 2026년 8월 3일
COLDCARD 엔트로피 결함: 조용한 RNG 폴백은 어떻게 사용자에게 3,800만 달러의 손실을 안겼나

주요 결과

  • COLDCARD Mk3에서 시드 문구를 생성·사용한 사용자: 즉시 다른 지갑에서 시드 문구를 다시 생성하고 자금을 새 지갑으로 이전하십시오.
  • COLDCARD Mk4 또는 Mk5에서 시드 문구를 생성·사용한 사용자: 원래 시드 문구를 생성한 펌웨어 버전이 5.6.0 미만이었다면, 즉시 다른 지갑에서 시드 문구를 다시 생성하고 자금을 이전하십시오.
  • COLDCARD Q에서 시드 문구를 생성·사용한 사용자: 원래 시드 문구를 생성한 펌웨어 버전이 1.5.0Q 미만이었다면, 즉시 다른 지갑에서 시드 문구를 다시 생성하고 자금을 이전하십시오.
  • OneKey 하드웨어 지갑 사용자는 이 버그의 영향을 받지 않으며 안심하고 계속 사용할 수 있습니다.

암호학에서 '무작위'는 엄격한 척도다. 정량화할 수 있어야 하고, 실제 연산 능력 앞에서도 견뎌내야 하는 것이다.

12단어 복구 문구는 128비트 난수에 뒷받침되며, BIP-39 명세에 따라 사람이 읽을 수 있는 단어로 인코딩된다. 이 숫자가 얼마나 예측 불가능한지가 지갑이 무차별 대입 공격을 견딜 수 있는지를 직접 좌우한다. 128비트는 2¹²⁸가지 경우를 의미한다. 지구상의 모든 연산 능력을 모아도 우주가 끝나기 전에 이를 전부 열거할 수는 없다.

그래서 이론상 하드웨어 지갑은 이 부분에 엄격해야 한다. 회로 잡음이라는 물리 세계의 무작위성을 취하는 전용 진성난수생성기(TRNG)가 있어야 하고, EAL 인증을 받은 보안 요소(SE)와 결합되며, 마지막에는 성숙한 알고리즘이 이 모든 것을 뒤섞어야 한다.

2026년 7월 30일, 500대에 가까운 COLDCARD 지갑에서 약 594 BTC(약 3,800만 달러)가 30분도 안 되어 빠져나갔다. 이튿날 제조사 Coinkite는 「Technical Deep Dive into the Entropy Issue」[1]에서 근본 원인을 확인했다. 2021년 3월의 펌웨어 변경 이후, 빌드 구성 오류로 인해 코드가 MicroPython 내장 소프트웨어 의사난수생성기(PRNG)로 조용히 폴백되고 있었던 것이다.

영향은 모델별로 다르다. Coinkite의 잠정 추정에 따르면, 설계 목표인 128비트에 비해 Mk3는 유효 탐색 공간이 약 40비트밖에 남지 않았고, Mk4·Mk5·Q는 약 72비트다. 40비트는 대략 1.1조 가지로 여전히 천문학적으로 들리지만, GPU 클러스터를 빌릴 여력이 있는 공격자에게는 '물리적으로 불가능'에서 '기댓값상 실현 가능한 공학 과제'로 내려앉았음을 뜻한다. 128에서 40으로, 탐색 공간은 2⁸⁸분의 1, 즉 30만×10²⁰분의 1로 줄어들었다.

이 3,800만 달러 규모의 도난은 그 기댓값을 기정사실로 바꿔 놓았다.

참고: OneKey 사용자의 자금은 안전합니다. OneKey의 코드는 이 문제에 전혀 관여하지 않으며, 관련된 구현이나 종속성도 사용하지 않습니다. 전체 성명: https://x.com/OneKeyHQ/status/2083106588022509974?s=20

TL;DR

  • COLDCARD Mk3에서 시드 문구를 생성·사용한 사용자: 즉시 다른 지갑에서 시드 문구를 다시 생성하고 자금을 새 지갑으로 이전하십시오.
  • COLDCARD Mk4 또는 Mk5에서 시드 문구를 생성·사용한 사용자: 원래 시드 문구를 생성한 펌웨어 버전이 5.6.0 미만이었다면, 즉시 다른 지갑에서 시드 문구를 다시 생성하고 자금을 새 지갑으로 이전하십시오.
  • COLDCARD Q에서 시드 문구를 생성·사용한 사용자: 원래 시드 문구를 생성한 펌웨어 버전이 1.5.0Q 미만이었다면, 즉시 다른 지갑에서 시드 문구를 다시 생성하고 자금을 새 지갑으로 이전하십시오.
  • OneKey 하드웨어 지갑 사용자는 이 버그의 영향을 받지 않으며 안심하고 계속 사용할 수 있습니다.

이제 본격적인 기술 파트로 들어간다 👇

근본 원인: 조용한 소프트웨어 폴백

하드웨어 RNG 인터페이스에서 libNgU로

2021년의 암호 스택 마이그레이션은 지갑 시드 생성을 ckcc.rng_bytes()에서 ngu.random.bytes()로 바꿨다 [6]:

ngu.random.bytes() → libNgU rng_get() → 최종적으로 링크되는 rng_get 심볼

위험은 함수 이름이나 출력 길이에 있지 않다. 그 최종 rng_get()을 실제로 어떤 오브젝트 파일이 공급하느냐에 있다.

#ifndef는 무언가가 정의되어 있는지만 검사할 뿐, 그 값은 검사하지 않는다

대상 보드 구성은 MICROPY_HW_ENABLE_RNG0으로 정의했는데, 이는 MicroPython의 하드웨어 RNG 경로가 활성화되지 않았음을 의미했다.

그러나 당시 libNgU는 다음과 같이 사용했다 [8]:

#ifndef MICROPY_HW_ENABLE_RNG
#error ...
#endif

#ifndef는 매크로가 존재하는지만 테스트한다. 0으로 정의된 매크로도 여전히 '정의됨' 상태이므로, 잘못된 빌드를 막아야 했던 #error는 한 번도 발동하지 않았다.

동일한 이름의 심볼이 잘못된 구현을 최종 펌웨어에 끼워 넣었다

하드웨어 RNG가 활성화되지 않았을 때에도 MicroPython은 같은 이름으로 rng_get()을 제공한다. 다만 그것은 Yasmarang 소프트웨어 PRNG 폴백이다 [9].

그렇게 전체 실패 연쇄가 완성됐다:

매크로는 존재하지만 값이 0 → libNgU의 빌드 가드가 발동하지 않음 → 펌웨어는 여전히 정상적으로 컴파일됨 → 동일한 이름의 rng_get이 MicroPython의 폴백으로 해석됨 → 시드 생성이 본래 받아야 할 하드웨어 RNG 입력을 받지 못함

하나씩 떼어 보면 이 연쇄의 각 고리는 사소한 실수에 불과하다. 그러나 엮이면 빌드 시스템의 문지기 역할을 무의미하게 만든다. 안전한 구현이 소스나 바이너리에 존재한다는 것이 보안상 중요한 호출이 실제로 그곳에 도달함을 의미하지는 않는다.

엔트로피 소스를 섞어도 없는 엔트로피를 메울 수는 없다

폴백의 초기 상태에는 UID의 일부, SysTick, RTC 시간, 초 미만 상태가 포함되며, 그 후 Yasmarang이 이를 결정론적으로 진행시킨다. libNgU는 또한 고정된 초기 상태에서 시작하는 두 번째 Yasmarang 스트림과 이를 혼합한다.

재구성하거나 열거할 수 있는 두 개의 결정론적 스트림은 XOR하거나 SHA-256을 통과시켜도 새로운 물리적 예측 불가능성을 얻지 못한다. 해싱은 입력을 정돈할 수는 있어도, 유한한 후보 집합을 진정한 2^256의 미지 공간으로 확장할 수는 없다.

40비트와 72비트가 실제로 의미하는 것

Coinkite가 사용하는 유효 탐색 공간 추정치는 측정되거나 인증된 엔트로피 값이 아니다. 이 두 숫자는 공격자가 처리해야 하는 후보 상태 공간의 크기를 묘사한다. min-entropy의 측정값이 아니며, 평균 추측 횟수로 환산되지도 않고, 더더욱 특정 공격 시간이나 비용을 도출하지도 않는다.

실제 공격 비용은 전제 조건의 연쇄에 달려 있다. 공격자가 기기 UID를 알거나 추측할 수 있는가; RTC, SysTick, 부팅 시간의 범위를 좁힐 수 있는가; 시드 생성 전에 몇 번의 RNG 호출이 발생했는가; 후보를 오프라인으로 검증할 xpub, 주소, 공개키를 손에 쥐고 있는가; 그리고 BIP-39/BIP-32 파생과 병렬 하드웨어 실행 비용이 얼마인가.

그러므로 정확한 표현은 이렇다. Coinkite의 현재 잠정 공격 가정하에서, Mk3의 유효 탐색 공간은 약 40비트로, Mk4/Q/Mk5는 약 72비트로 추정된다. 이는 '모든 Mk3 지갑이 정확히 40비트의 엔트로피를 갖는다'는 것과 같지 않고, '최신 모델이 72비트의 암호학적 보안을 갖는다고 입증되었다'는 것도 아니며, 물론 '어떤 평범한 컴퓨터라도 정해진 시간 안에 모든 지갑을 복원할 수 있다'는 것은 더더욱 아니다.

왜 Mk4, Mk5, Q도 영향을 받는가

Mk5와 Q 보드에 있는 두 개의 보안 요소(출처: coldcard.com)Mk5와 Q 보드에 있는 두 개의 보안 요소(출처: coldcard.com)

Mk5와 Q 보드에 있는 두 개의 보안 요소(출처: coldcard.com)

Mk4, Mk5, Q는 실제로 두 개의 보안 요소에서 무작위 재료를 끌어오지만, 수정 전 구현은 그 출력 전체를 암호학적 DRBG에 투입하지 않았다.

공개 소스를 보면, 보안 요소 재료를 해싱한 뒤 단 4바이트만 취해 ngu.random.reseed()에 넘기고, Yasmarang의 32비트 상태 워드를 단 하나만 교체한다.

따라서 폴백 상태의 나머지와 호출 트레이스가 고정되어 있을 때:

보안 요소 재시드로 구별 가능한 출력 스트림 수 ≤ 2³²

이는 공식 '약 72비트'와 모순되지 않는다. 72비트 모델은 UID, 타이머, RTC, 호출 이력 같은 상태의 불확실성도 함께 계산한다. Block Engineering의 느슨한 결합 상한은 2^73.3 아래로 나오며, 이것이 73비트 암호학적 보안의 인증은 아니라고 명시적으로 밝히고 있다 [10].

다시 말해, Mk3는 최악의 경우다. 안전한 재시드가 전혀 없기 때문이다. Mk4/Q/Mk5의 보안 요소 입력은 위험을 낮추지만, 4바이트 재시드로는 설계가 목표했던 128비트 보안을 복원하지 못한다.

공식 권고와 실제 범위

Coinkite의 현재 권고는 Mk3 4.0.1부터 시작한다. 그러나 변경 불가능한 v4.0.0 소스에는 이미 해당 엔트로피 생성 경로가 포함되어 있으며 [7], 4.0.0과 4.0.1 사이에 대응하는 RNG 수정은 없다.

Block Engineering은 한발 더 나아가 Mk2/Mk3 v4.0.0~v4.1.9까지 소스 분석에 포함한다 [10].

따라서 구분해야 할 두 가지 층위가 있다:

  • Coinkite의 공식 범위: Mk3 4.0.1 이상;
  • 소스 코드가 뒷받침하는 기술적 범위: Mk2/Mk3 v4.0.0~v4.1.9.

Coinkite가 Mk2나 v4.0.0을 공식적으로 확인했다고 말할 수 없다. 동시에 권고가 그것들을 지명하지 않았다는 이유만으로 안전하다고 추론할 수도 없다.

수정은 어떻게 작동하는가

Mk4/Mk5 5.6.0과 Q 1.5.0Q의 핫픽스는 조건식 하나를 바꾸는 것 이상을 했다. 빌드 수준의 강제를 추가한 것이다 [3][4][5]:

  • MicroPython의 폴백 RNG 오브젝트를 제외한다;
  • 보드 수준 오브젝트가 전역 rng_get()을 제공하는지 확인한다;
  • nm을 사용해 오브젝트 파일의 심볼을 검사한다;
  • 폴백이 여전히 그 심볼을 내보내거나, 보드 수준 오브젝트가 rng_get()을 제대로 제공하지 않으면 빌드를 즉시 실패시킨다.

사용자가 해야 할 일

Mk4, Mk5, Q

  1. 먼저 5.6.0 이상(Mk4/Mk5) 또는 1.5.0Q 이상(Q)으로 업데이트하십시오.
  2. 수정된 펌웨어에서 완전히 새로운 시드를 생성하십시오.
  3. 백업을 기록하고 복원 검증을 완료하십시오.
  4. 기기 화면에서 지갑 지문과 수신 주소를 확인하십시오.
  5. 나머지 자금을 이전하기 전에 소액 테스트 거래를 보내십시오.
  6. 모든 이체가 확인될 때까지 기존 백업은 보관하되, 기존 지갑으로의 수신은 중단하십시오.

Mk3

현재 Mk3용 수정 펌웨어는 출시되지 않았으며, 4.1.9는 수정본이 아닙니다. 나중에 나올지 모를 펌웨어를 기다려서는 안 됩니다. 어떤 새 펌웨어도 기존 시드에 엔트로피를 추가할 수 없기 때문입니다.

Coinkite의 현재 이전 지침을 따르십시오. 신뢰할 수 있는 경로에서 새 시드를 생성하고, 백업, 주소, 소액 거래를 검증한 뒤 자산을 이전하십시오.

서로 다른 두 개의 주사위 기준값

주사위에는 두 개의 숫자가 있다: 50과 99. 둘은 서로 다른 목표에 쓰이며 서로 바꿔 쓸 수 없다.

원래 시드 생성 시 추가한 50회 이상의 굴림. 시드를 처음 생성할 때 기록·저장·공개된 적이 없는 공정하고 독립적인 개인 6면체 주사위 굴림이 최소 50회 섞여 있었다면, Coinkite는 그 RNG 문제만으로는 해당 시드가 위험에 처했다고 보지 않는다고 밝혔다 [11].

50 × log₂(6) ≈ 129.25비트

이는 이 특정 사건에 대한 대략 128비트 기준값이며, 당신의 운영 프로세스 전체에 대한 절대적 보안 증명은 아니다.

빈 Mk3에서의 Dice Roll Import 흐름. Coinkite는 또 다른 흐름도 제공한다. 4.1.9를 실행하는 빈 Mk3에서 Import Existing > Dice Rolls를 선택하고 최소 99회의 공정한 굴림을 입력한다. 이 전용 경로는 주사위 시퀀스를 직접 소비하며 영향을 받은 기기 생성기를 사용하지 않는다.

99 × log₂(6) ≈ 255.91비트

99는 공식 흐름에서의 기준값이며, 문자 그대로 '최소 256비트' 기준에서 거꾸로 계산하면 100회가 필요하다.

패스프레이즈는 별개의 장벽이지, 해결책이 아니다

강력하고 고유하며 무작위인 비밀 BIP-39 패스프레이즈는 다른 지갑을 파생시키고 독립적인 탐색 요소를 추가할 수 있다. 기기 PIN은 로컬 접근만 제어하며 BIP-39 루트 키 파생에는 전혀 관여하지 않는다 [12].

그러나 패스프레이즈는 니모닉이 애초에 갖지 못한 엔트로피를 메울 수 없다. 짧은 패스프레이즈, 유명한 인용구, 예측 가능한 패턴, 재사용된 비밀번호는 여전히 추측될 수 있다. 오타 또한 겉보기에는 유효하지만 완전히 다른 지갑을 생성하므로, 지문을 검증하고 복원을 테스트해 본 신뢰할 수 있는 백업을 보관해야 한다.

맺음말

이 사건이 드러낸 핵심 문제는, 보안상 중요한 구현의 실제 도달 가능성이 빌드 시스템에 의해 한 번도 강제되지 않았다는 점이다. '누군가 매크로를 잘못 썼다'로는 도저히 설명할 수 없다.

최소한 하드웨어 지갑과 기타 키 생성 시스템은 다음을 수행해야 한다:

  • 보안 API가 최종적으로 어떤 오브젝트와 심볼에 링크되는지 검증하고, 함수 시그니처만 확인하지 말 것;
  • 능력 검사에서 매크로의 존재와 값을 모두 검증할 것;
  • 보안상 중요한 폴백을 페일 클로즈로 만들어, 평범한 PRNG를 조용히 공급하는 일이 결코 없도록 할 것;
  • CI가 오브젝트 구성, 링크 맵, 심볼 출처, 엔드투엔드 데이터 흐름을 검사하도록 할 것;
  • 출력 길이나 0이 아님, 반복 없음만 확인하지 말고, 실제 하드웨어 엔트로피가 최종 시드에 도달함을 테스트로 증명할 것;
  • 시드를 생성한 버전, 현재 펌웨어, 수정 버전, 그리고 기존 시드를 어떻게 해야 하는지를 명확히 구분한 권고문을 작성할 것.

COLDCARD의 오픈소스가 있었기에 외부 연구자들이 이 호출 연쇄를 재구성할 수 있었고, Coinkite는 공식 기술 보고서와 수정 릴리스를 모두 공개할 수 있었다.

어떤 브랜드를 '절대적으로 안전하다'고 주장하는 것은 아무 가치가 없다. 가치 있는 것은 '무작위성이 어디에서 오고, 최종적으로 무엇에 링크되며, 실패 시 어디로 향하고, 이를 출하된 제품 안에서 어떻게 검증하는가'를 몇 번이고 다시 확인할 수 있는 시스템적 속성으로 만드는 것이다.

참고 문헌

[1] Coinkite: Technical Deep Dive into the Entropy Issue [2] Coinkite: Mk3 Security Advisory [3] Coldcard 5.6.0 / 1.5.0Q fix commit [4] Coldcard 5.6.0 release commit [5] Coldcard 1.5.0Q release commit [6] 2021 libNgU seed generation migration commit [7] Official v4.0.0 source snapshot [8] libNgU random.c [9] MicroPython commit introducing the fallback [10] Block Engineering technical analysis [11] Coldcard dice roll math [12] Coldcard passphrase documentation [13] OneKey trezorcrypto.random source branch [14] OneKey seed generation logic [15] OneKey standard Makefile [16] OneKey SCons config

OneKey로 암호화 여정 보호하기

View details for OneKeyOneKey

OneKey

세계에서 가장 진보한 하드웨어 지갑.

View details for 앱 다운로드앱 다운로드

앱 다운로드

글로벌 자산을 거래하세요. 이메일만으로 몇 분 안에 시작할 수 있습니다.

View details for OneKey SifuOneKey Sifu

OneKey Sifu

암호화 의문을 해결하기 위해, 한 번의 전화로.

계속 읽기