Уязвимость Coldcard: сид-фразы генерировались не случайно
30 июля 2026 года за 25 минут с примерно пятисот биткоин-кошельков исчезло 594 BTC — на тот момент около $38 миллионов. Владельцы этих кошельков не переходили по фишинговым ссылкам, не вводили сид-фразу на постороннем сайте и не подключали устройство к интернету. Часть из них не открывала кошелёк месяцами. Устройство, в котором хранились ключи — Coldcard, один из самых уважаемых аппаратных кошельков на рынке, специально спроектированный так, чтобы никогда не касаться сети.
Один физический бросок костей — случайность, которую нельзя сломать строкой кода.
К вечеру того же дня стало ясно: это не единичный случай. К началу августа сумма выросла до $89 миллионов с более чем 4,5 тысяч адресов. Причина — не кража. Причина в том, что сид-фраза этих кошельков никогда не была по-настоящему случайной.
Что произошло технически
Чтобы создать кошелёк, устройство должно выбрать случайный набор из 12 или 24 слов — сид-фразу. От того, насколько по-настоящему случаен этот выбор, зависит всё: если варианты можно предсказать или перебрать, кошелёк уязвим, даже если он никогда не был в сети и владелец всё делал правильно.
В марте 2021 года в прошивку Coldcard закралась ошибка в одной строке кода. Из-за неё устройство тихо переключалось со специального аппаратного генератора случайных чисел на программный — более быстрый, но предсказуемый, если знать, с чего он стартовал. А стартовал он с данных, которые не являются секретом: уникального идентификатора чипа и показаний таймера.
Разработчики Coldcard оценивают: вместо ожидаемых 128 бит энтропии (число вариантов настолько огромное, что перебрать их нереально) устройства с этой прошивкой выдавали около 40 бит. Разница не в разах — это разница между «перебрать невозможно даже всем компьютерам мира» и «перебрать реально на обычном игровом компьютере за разумное время». Судя по всему, атакующие использовали автоматизированный анализ кода, чтобы найти уязвимость раньше, чем это сделала сама компания — производитель, Coinkite, утверждает, что код всегда был в открытом доступе.
Кого это касается
Под угрозой — Coldcard Mk3 с прошивкой версий 4.0.1–4.1.9, если сид-фраза создавалась без дополнительных бросков костей (опция, добавляющая независимую случайность) и без BIP-39 пароля-фразы. Более новые модели — Mk4, Mk5, Q — используют другую прошивку и, по данным компании, этой конкретной ошибкой не затронуты. Кошельки других производителей (Trezor, Ledger) тоже не задеты — у них другой код, а случайность собирается сразу из нескольких независимых источников, а не одного.
Важно понимать: это не история про то, что «аппаратные кошельки — плохая идея». Это история про то, что даже правильное поведение владельца — offline-хранение, никогда не вводить фразу онлайн, никому её не показывать — не защищает, если сама фраза изначально не была случайной. Проверить это со стороны пользователя невозможно: сид-фраза выглядит одинаково случайно, независимо от того, из скольких реальных вариантов её выбирали.
Что делать прямо сейчас
Если вы пользуетесь Coldcard — три проверяемых шага:
Обновите прошивку. Для Mk3 — версия 4.2.0 или новее, для Mk4/Mk5 — 5.6.0+, для Q — 1.5.0Q+. Обновление прошивки не чинит уже существующую сид-фразу — оно только чинит генератор для будущих фраз.
Сгенерируйте новую сид-фразу после обновления и переведите на неё средства. Перенос старой фразы на новую прошивку не помогает — уязвимость была не в прошивке как таковой, а в том, как была выбрана сама фраза, и задним числом это не исправить.
Если не помните, использовали ли вы броски костей или пароль-фразу при создании — считайте, что не использовали. Компания прямо говорит: при неуверенности переносите средства, это надёжнее, чем гадать.
Если у вас Ledger, Trezor или другой производитель — эта конкретная уязвимость вас не касается.
Суть проблемы
У этой истории неприятная особенность: слабость молча существовала пять лет, никак себя не проявляя, пока кто-то не начал целенаправленно искать дыры в открытом коде. Ни один чек-лист «как правильно хранить крипту» не предупреждал об этом — предупреждать было не о чем, пока баг не нашли.
Стоит быть честным: это история не про украденный ключ, а про ключ, который изначально не был по-настоящему случайным — и второй ключ здесь бы не спас, если бы он был создан тем же сломанным способом. Но у крипто-хранения есть и другая, более частая проблема: даже безупречно сгенерированный ключ остаётся единственной точкой отказа, если именно он один способен санкционировать любую операцию. Для этой, второй проблемы решение простое — требовать подтверждение крупной операции ещё одним, отдельно хранимым ключом, чтобы утрата или компрометация одного секрета не означала автоматическую потерю всего.