Back to Blog

Инцидент с COLDCARD: когда «случайная» сид-фраза кошелька оказалась не случайной

Code Auditing
August 7, 2026
15 min read
Key Insights
  • Потери COLDCARD обусловлены единственной ошибкой конфигурации сборки — макро-охранник проверял наличие (#ifndef) вместо значения (#if), молча перенаправляя генерацию seed-фразы на детерминированный программный запасной RNG.

  • Атака была полностью офлайновой: никаких эксплойт-транзакций в сети, только перебор seed-фраз (~40 бит на Mk2/Mk3, ~72 бита на Mk4/Q/Mk5) с сопоставлением против публичных данных кошельков.

  • Обновление прошивки не исправляет уже сгенерированные seed-фразы — скомпрометированные средства необходимо перевести на новую seed-фразу, созданную в исправленном выпуске.

  • Этот случай демонстрирует, почему криптографические пути энтропии должны отказывать безопасно и проверяться сквозным образом в финальной прошивке, а не только во время компиляции.

Краткое резюме

Начиная с 30 июля 2026 года, средства были выведены с аппаратных Bitcoin-кошельков COLDCARD в несколько волн, которые продолжали разворачиваться в последующие дни. Не было ни единой атакующей транзакции в блокчейне, ни уязвимого смарт-контракта; потери стали следствием офлайн-проблемы восстановления сид-фразы с последующими on-chain-выводами средств. По состоянию на 7 августа 2026 года on-chain-отслеживание подтвердило минимальный объём примерно в 1 405 BTC (~$91M по цене $64 700 на 7 августа), выведенных примерно с 4 925 адресов [1], атрибуция по волнам достигла около 1 433 BTC в рамках десяти волн [2], а сверка с пострадавшими по закрытым каналам дала цифру вплоть до 2 055 BTC (~$133M) [3].

Первопричиной стал сбой энтропии кошелька: при миграции прошивки в 2021 году генерация сид-фразы была направлена через ngu.random.bytes(), который откатился к детерминированному программному генератору вместо предполагаемого аппаратного ГСЧ STM32. Для затронутых устройств это превратило восстановление сид-фразы из криптографически неразрешимой задачи в офлайн-перебор, позволив злоумышленнику перечислять кандидатные сид-фразы и сопоставлять их с публичными данными кошельков для восстановления приватных ключей. Опираясь на наш предыдущий еженедельный анализ инцидента, данное углублённое исследование количественно оценивает остаточную энтропию для каждого поколения затронутых устройств, отслеживает способы идентификации пострадавших и похищенных средств в блокчейне, а также рассматривает отдельную регрессию прошивки после выпуска хотфикса, способную вызвать отказ в обслуживании до авторизации.

Предыстория

COLDCARD — это аппаратный Bitcoin-кошелёк. Как и в других кошельках с самостоятельным хранением, его безопасность в конечном счёте зависит от непредсказуемости сид-фразы, генерируемой при настройке кошелька. Сид-фраза BIP-39 читабельна человеком, однако базовое свойство безопасности по-прежнему определяется энтропией случайных байтов, использованных при её создании. Если вывод генерации сид-фразы предсказуем, безопасность кошелька рушится — сколь бы тщательно сид-фраза ни хранилась впоследствии.

COLDCARD охватывает аппаратные ревизии от Mk1 до Mk5 и модель Q. Mk2 и Mk3 используют устаревшую линейку прошивок. Mk4, Mk5 и Q используют отдельные ветки релизов Standard и Edge.

Большая часть логики приложения COLDCARD написана на Python и выполняется на MicroPython, а нативные модули на C обеспечивают аппаратные и криптографические операции. Безопасный путь генерации сид-фразы должен считывать 32 байта из аппаратного ГСЧ STM32, завершаться с ошибкой при зависании периферии или повторении значения, хэшировать результат, а затем кодировать его в виде слов BIP-39. В версии v3.2.2 make_new_wallet() следовал именно этому пути:

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

Анализ уязвимости

Первопричиной стала ошибка сборки и интеграции, связанная с MICROPY_HW_ENABLE_RNG. В конфигурации производственной платы COLDCARD этот макрос был установлен в 0, поскольку прошивка использовала собственную локальную обёртку аппаратного ГСЧ вместо реализации аппаратного ГСЧ MicroPython. Однако путь генерации кошелька был перенесён на ngu.random.bytes(32), а STM32-путь libngu в конечном счёте зависел от глобального символа rng_get().

Затронутый путь входил в my_random_bytes() библиотеки libngu. Для каждого выходного слова выполнялась операция XOR значения, возвращаемого CHIP_TRNG_32(), с собственным выводом Yasmarang:

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: public initial state
            |         `- Mk4/Q/Mk5: 32-bit pad reseed
            |
            `- output = Yasmarang A XOR Yasmarang B

Yasmarang A был программным запасным вариантом MicroPython за rng_get(), инициализируемым из состояния устройства и таймеров. Yasmarang B принадлежал libngu: на Mk2/Mk3 он использовал публичные начальные значения, тогда как на Mk4/Q/Mk5 только 32-битное слово pad заменялось данными из защищённого элемента. Локальный аппаратный ГСЧ STM32 по-прежнему существовал, но ngu.random.bytes() его не вызывал.

Несоответствие непосредственно видно в конфигурации сборки. Файл mpconfigboard.h для Mk4 отключал ветку аппаратного ГСЧ MicroPython:

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

CHIP_TRNG_32() библиотеки libngu по-прежнему считал наличие макроса достаточным доказательством аппаратного ГСЧ, поскольку проверял лишь факт существования макроса, а затем вызывал rng_get():

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

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

Эта проверка упускает опасный случай: макрос, определённый как 0, всё равно определён. Сборка поэтому завершилась успешно, а rng_get() разрешился в STM32 RNG-модуль MicroPython вместо отдельной локальной обёртки COLDCARD (random32() / random_buffer(), доступной в Python как ckcc.rng_bytes). В выборе rng_get() в MicroPython условие MICROPY_HW_ENABLE_RNG == 0 выбирало программную запасную ветку:

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

Mk2/Mk3: около 40 бит

Скомпилированный запасной вариант pyb_rng_yasmarang() инициализировал и продвигал Yasmarang следующим образом:

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);
}

Переменные занимают 104 бита, однако размер состояния не равен энтропии. dat начинается с нуля, а остальные значения представляют собой фиксированные метаданные или коррелированные показания таймеров, а не независимые секреты. В рамках приближённой модели Mk2/Mk3, используемой для оценки примерно в 40 бит:

Входное значение Возможные значения Стоимость перебора
Известный UID_low32 1 2^0
SysTick->VAL 80 000 2^16.29
RTC->TR время суток 86 400 2^16.40
RTC->SSR субсекунды 256 2^8

Рассматривая все поля таймеров как независимые, получаем намеренно широкий верхний предел:

80,000 * 86,400 * 256
= 1,769,472,000,000
= 2^40.69 candidate initial states

Полный перебор требует не более 2^40.69 попыток и, при допущении о равномерном распределении, в среднем около 2^39.69 попыток. Это верхняя граница перебора, а не 40 бит криптографической энтропии. Если регистры RTC статичны во время обычной холодной загрузки, остаётся только SysTick, что снижает верхнюю границу примерно до 2^16.29. Если UID, значения таймеров и количество предшествующих вызовов ГСЧ известны, существует ровно один поток: 2^0. Неизвестная история вызовов добавляет лишь количество вероятных трасс выполнения, а не новый источник энтропии. Аналогично, генерация восьми 32-битных слов для 256-битной сид-фразы не умножает пространство поиска: каждое слово определяется одним и тем же начальным состоянием.

На уровне libngu my_random_bytes() смешивал описанный выше запасной вариант MicroPython с отдельным генератором Yasmarang из libngu. В исходном коде буквально нет chip = rng_get(): CHIP_TRNG_32() раскрывается в rng_get(). На Mk2/Mk3 второй генератор начинал с публичных констант:

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();

Таким образом, оба потока были воспроизводимы, как только становились известны состояние запасного варианта MicroPython и история вызовов. XOR изменял выходные значения, но не добавлял энтропии. Даже если UID_low32 неизвестен, выражение UID_low32 ^ SysTick всё равно сворачивает оба входа в одно 32-битное значение pad; их номинальное количество бит не суммируется.

Mk4/Q/Mk5: около 72 бит

В более поздних моделях сохранялась та же двухгенераторная конструкция, но rng_seeding() добавлял материал из защищённого элемента в генератор libngu во время загрузки:

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)

Несмотря на то что в хэш поступало 40 байт, до reseed() доходили лишь первые четыре байта результата [4]. Реализация random_reseed() затем заменяла только 32-битное слово pad в libngu:

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

Остальные слова состояния libngu сохраняли свои публичные значения, а запасной вариант MicroPython не пересевался. Приблизительная цифра в 72 бита складывается из 32-битного ресида libngu и приблизительного верхнего предела для состояния таймеров более поздних моделей:

MicroPython fallback:
    120,000 SysTick values * 86,400 RTC times * 256 subseconds
    = 2^41.27 states

Libngu secure reseed:
    2^32 values

Combined ceiling:
    2^41.27 * 2^32 = 2^73.27 candidates

Average enumeration:
    2^73.27 / 2 = 2^72.27 trials

Отсюда берётся цифра «около 72 бит». Это оценка среднего объёма работы атакующего, а не 72 бита, предоставленных защищёнными элементами. Поля таймеров коррелированы и могут быть восстановлены; если состояние запасного варианта MicroPython известно, остаётся лишь 2^32 значений ресида, в среднем 2^31 попыток. Хэширование финальных 32 случайных байтов не может увеличить количество возможных сид-фраз.

Затронутые версии

Устройство и ветка Вне данной регрессии Затронутые версии прошивки для генерации сид-фразы Эффективная битовая безопасность Первый исправленный релиз
Mk1 До v3.0.6 Нет - Н/Д
Mk2/Mk3 До v3.2.2 v4.0.0–v4.1.9 (по официальному advisory — с v4.0.1) Около 40 бит при наличии уязвимости v4.2.0
Mk4/Mk5 Standard Н/Д До v5.6.0 Около 72 бит до исправления; не менее 128 бит после v5.6.0
Q Standard Н/Д До v1.5.0Q Около 72 бит до исправления; не менее 128 бит после v1.5.0Q
Mk4/Mk5 Edge Н/Д До v6.6.0X Около 72 бит до исправления; не менее 128 бит после v6.6.0X
Q Edge Н/Д До v6.6.0QX Около 72 бит до исправления; не менее 128 бит после v6.6.0QX

Значимой является версия прошивки, которая генерировала сид-фразу, а не версия, установленная в данный момент. Новые сид-фразы, сгенерированные в исправленных релизах и позднее, используют скорректированный путь, однако обновление не исправляет уже существующую сид-фразу. Официальный диапазон затронутых версий для Mk2/Mk3 начинается с v4.0.1 [5], тогда как анализ исходного кода также включает v4.0.0 [4]. Независимая энтропия кубиков может повысить безопасность сид-фразы, тогда как надёжная парольная фраза BIP-39 добавляет отдельный барьер, не исправляя саму сид-фразу [6].

Best Security Auditor for Web3

Validate design, code, and business logic before launch

Отслеживание пострадавших и средств

Атакующей транзакции в блокчейне для отслеживания не существовало; восстановление происходило исключительно в офлайн-режиме. Нацелившись на сид-фразу, сгенерированную уязвимой прошивкой, злоумышленник мог ограничить и перебрать описанные выше кандидатные состояния ГСЧ, воспроизвести поток генерации сид-фразы для каждого кандидата, вывести из него ключи кошелька и сопоставить их с публичными данными кошельков, а затем вывести средства из найденных пополненных кошельков в блокчейне. Это затрагивало только кошельки, выводимые из одной сид-фразы: надёжная уникальная парольная фраза BIP-39 подмешивает независимую энтропию, предоставленную пользователем и никогда не затронутую уязвимостью ГСЧ, в процесс выведения ключей через PBKDF2, выводя такие кошельки за рамки чистого перебора сид-фраз. Выведенные кошельки по необходимости не имели такой защиты [6]. Поскольку кража проявилась лишь в виде on-chain-выводов, а не отслеживаемого эксплойта, идентификация пострадавших и отслеживание средств стали задачей on-chain-криминалистики.

Несколько независимых усилий отслеживали похищенные средства: публичные сайты мониторинга (Coldcard Sweep Watch [1], coldcard.rip [2] и Coldcard Hack Tracker [7]) и частная сверка Galaxy Research [3] с пострадавшими, при этом их суммарные данные сравниваются ниже. Поскольку Coldcard Sweep Watch опубликовал свою методологию, мы используем её для иллюстрации процесса идентификации — цикла обратной связи между офлайн-отчётами и on-chain-анализом:

  1. Офлайн-якоря. Пострадавшие и исследователи предоставляли публичные адреса или идентификаторы транзакций, а при наличии — контекст устройства и генерации сид-фразы. Каждое сообщение рассматривалось как зацепка и проверялось в блокчейне; сид-фраза, приватный ключ или xpub не требовались.
  2. On-chain-расширение. Начиная с подтверждённых якорей, сканеры искали в соответствующих блоках те же характеристики вывода: опустошённые кошельки без сдачи, схожие типы входов, плотный временной интервал, повторяющиеся комиссии, общие адреса назначения или последующие совместные траты.
  3. Офлайн-перекрёстные проверки. Новые сообщения пострадавших, наборы данных исследователей и атрибуция сервисов использовались для подтверждения или отклонения кандидатных волн. Проверенные кластеры и эвристические кандидаты оставались раздельными.

Bitcoin идентифицирует адреса, а не людей или модели кошельков. Один кошелёк может управлять множеством адресов, поэтому количество адресов не равно количеству пострадавших. Первая широко освещавшаяся крупная волна, 960188, составила 594,48 BTC; продолжение сканирования и поступление новых сообщений увеличивали общую сумму. По состоянию на 7 августа 2026 года Coldcard Sweep Watch зафиксировал подтверждённый минимум около 1 405,07 BTC (~$91M по цене $64 700 на 7 августа) примерно с 4 925 адресов [1], тогда как снимок coldcard.rip от 3 августа атрибутировал до 1 433,13 BTC брутто, 1 432,48 BTC на адреса назначения после вычета комиссий, с 5 477 адресов в рамках десяти волн [2]. Отдельная частная сверка Galaxy Research, основанная на переписке с пострадавшими, дала ещё более высокую цифру — от около 1 596 BTC до 2 055 BTC (~$133M по той же цене) [3]. Расхождения объясняются разными порогами доказательности, временем обнаружения и каналом подтверждения, на который опирается каждый из трекеров.

Затем средства отслеживались через три наблюдаемых слоя: исходные адреса вывода, прямые адреса назначения вывода (holding) и последующие адреса консолидации (vault). В таблице показано количество уникальных адресов на каждом слое:

Паттерн Примеры маршрутов Следствие для отслеживания
Множество выводов на один или два holding-адреса, затем один vault 960183: 204 -> 2 -> 1; 960188: 500 -> 1 -> 1 Конвергенция адресов назначения делает кластер сравнительно надёжным и лёгким для отслеживания
Выводы останавливаются на holding-адресах без дальнейшей консолидации 960352: 352 -> 1 -> 0; 960668: 795 -> 1 -> 0 Holding-адрес остаётся отслеживаемым, однако последующих совместных трат для усиления атрибуции нет
Свежие адреса назначения для каждого вывода, иногда с последующими отдельными vault-адресами 960359: 13 -> 13 -> 0; 960395: 1 918 -> 294 -> 293 Детектор общего коллектора не срабатывает; группировка зависит от временно́го интервала, размера комиссии, шаблона транзакции и внецепочечного подтверждения

При движении отслеживаемых выходов анализ следует за разбиениями, слияниями и цепочками снятия сдачи, сохраняя стоимость за вычетом комиссий и ограничивая атрибуцию суммой вывода. Средства, поступающие на биржу или другой сервис с объединёнными средствами, снижают уверенность; такой сервис не добавляется в кластер злоумышленника.

Explore MetaSleuth Investigation

Trace flows and build evidence for investigations

Try now for free

Исправление, которое потребовало исправления: потенциальная регрессия с риском «окирпичивания»?

Отдельно от сбоя энтропии, хотфикс, устранивший его, привнёс самостоятельную регрессию прошивки [8, 9]. При восстановлении пути к аппаратному ГСЧ исправление оставило необработанным состояние ошибки аппаратного сида, что может вызвать отказ в обслуживании до авторизации и повлекло утверждения о безвозвратном «окирпичивании» устройств. Насколько это более серьёзное утверждение справедливо, зависит от деталей на уровне регистров.

Аппаратный ГСЧ STM32 предоставляет регистр управления (RNG_CR), регистр статуса (RNG_SR) и 32-битный регистр данных (RNG_DR). Релевантные статусные биты:

Бит Роль
RNGEN Включает ГСЧ и его аналоговые источники шума
DRDY Указывает, что данные готовы в RNG_DR; программа всё равно должна отклонять нулевые значения
SECS / SEIS Текущий сбой теста качества сида / зафиксированный статус ошибки сида
CECS / CEIS Текущая неисправность тактирования ГСЧ / зафиксированный статус ошибки тактирования

Различие между текущим и зафиксированным статусом существенно. SECS описывает текущее состояние источника шума, тогда как SEIS фиксирует факт возникновения ошибки сида до явной очистки программным обеспечением. На STM32L4S семейства Mk4/Q ошибка сида останавливает генерацию новых случайных чисел; на STM32L4 для Mk3 данные могут оставаться доступными, но доверять им нельзя. Ошибки тактирования являются отдельным случаем и не вызывают данной блокировки из-за ошибки сида.

Требуемая последовательность восстановления зависит от поколения STM32:

Семейство устройств Документированное восстановление после ошибки сида
Mk3 STM32L4 (RM0351, управление ошибками ГСЧ [10]) Сбросить SEIS, затем сбросить и установить RNGEN
STM32L4S семейства Mk4/Q (RM0432, управление ошибками ГСЧ [11]) Сбросить SEIS, прочитать и отбросить 12 слов RNG_DR, затем убедиться, что SEIS остаётся сброшенным

Хотфикс для устранения уязвимости энтропии от 31 июля корректно обеспечил разрешение rng_get() в аппаратный TRNG, однако rng_get_or_fault() семейства Mk4/Q не реализует никакого восстановления после ошибки сида. rng_init() действует только при сброшенном RNGEN, тогда как цикл чтения проверяет лишь DRDY. Если ошибка сида оставляет RNGEN включённым, но подавляет DRDY, инициализация становится бесполезной операцией; каждое чтение ждёт 10 мс и выбрасывает OSError(EFAULT) без очистки SEIS.

Это может затронуть пользовательский интерфейс до авторизации. Как mempad._start_scan() для цифровой клавиатуры, так и keyboard._start_scan() для Q перемешивают порядок сканирования по прерыванию от нажатия клавиши. Исключение ГСЧ там может заблокировать ввод PIN-кода и обычное меню обновления прошивки до конца данной аппаратной сессии.

Отказ на уровне кода является достоверным, однако более серьёзное утверждение о «постоянном окирпичивании» не подтверждено. Биты управления и статуса ГСЧ сбрасываются в ноль при аппаратном сбросе, поэтому единичная временная ошибка не должна необратимо повредить периферию; сохранение состояния после полного цикла питания не было продемонстрировано. Равным образом не существует продемонстрированного удалённого или надёжно контролируемого способа вызвать сбой теста качества сида. Пост в X [8] называл «окирпичивание» подтверждённым, однако указанный в нём PR, поданный сообществом PR #692 [9], содержит собственное заявление автора о том, что он анализировал сбой с помощью макета регистров, не воспроизвёл его на реальном оборудовании Mk4/Q и не подтвердил самостоятельно полевые отчёты. Наиболее обоснованная классификация — это потенциальный отказ в обслуживании до авторизации и регрессия надёжности, но не подтверждённая атака с постоянным «окирпичиванием».

Собственное исправление разработчиков, PR #693 [12], проверяет флаги ошибок сида, добавляет ограниченное восстановление с повторными попытками, отклоняет подозрительные образцы и перехватывает только ожидаемые ошибки клавиатуры; оно было влито 5 августа 2026 года, вытеснив поданный сообществом PR #692 [9], который был закрыт без слияния 4 августа 2026 года.

Заключение

Данный инцидент представлял собой сбой энтропии кошелька, превративший восстановление сид-фразы из криптографически неразрешимой задачи в задачу офлайн-поиска для затронутых устройств и рабочих процессов. Ключевой инженерной ошибкой стало то, что поставляемая прошивка не проверяла, действительно ли критически важный для безопасности API генерации сид-фразы обращается к предполагаемому аппаратному ГСЧ. Защитные проверки сборки должны проверять как факт существования макроса, так и его значение, запасные варианты для криптографической энтропии должны завершаться с ошибкой в закрытом состоянии, а CI должен проверять происхождение символов и сквозной поток энтропии в финальном образе прошивки. Для пострадавших пользователей решением не является обновление прошивки: обновление не исправляет сид-фразу, уже сгенерированную по уязвимому пути, а последующее добавление парольной фразы не защищает средства, уже хранящиеся на адресах данной сид-фразы. Эти средства необходимо перевести в кошелёк, созданный на основе новой сид-фразы в исправленном релизе; только средства, уже защищённые надёжной уникальной парольной фразой, оставались вне досягаемости чистого перебора сид-фраз [6].

Ссылки

Sign up for the latest updates
~$88M Потеряно: Эксплойты COLDCARD и LULA | Еженедельник BlockSec
Security Insights

~$88M Потеряно: Эксплойты COLDCARD и LULA | Еженедельник BlockSec

За неделю 27 июля–2 августа 2026 года два инцидента привели к потерям ~$88M. COLDCARD: ошибка энтропии прошивки аппаратного кошелька — неверная проверка макроса RNG направляла генерацию сида на детерминированный фолбэк, позволив украсть 1370 BTC (~$88M). LULA (BNB Chain): логическая уязвимость позволила вызвать `recycle()`, слив ~$578K из пула PancakeSwap V2.

Информационный бюллетень — июль 2026
Security Insights

Информационный бюллетень — июль 2026

Три крупнейших инцидента DeFi в июле 2026 года: потери ~$67,9M в сетях Arbitrum и Solana. AFX Trade: ~$24,15M из-за атаки на цепочку поставок. Ostium: ~$23,75M через скомпрометированный оракул. BonkDAO: ~$20M через захват голосования за $4,4M.

~$39,5 млн потеряно: Allbridge, Wanchain и другие | Еженедельник BlockSec
Security Audits

~$39,5 млн потеряно: Allbridge, Wanchain и другие | Еженедельник BlockSec

За неделю 20–26 июля 2026 г. произошло 8 инцидентов с потерями ~$39,5M в сетях Solana, Ethereum, BNB Chain, Arbitrum, Zilliqa и Cardano. Allbridge Core (~$1,65M): уязвимость валидации Solana. Wanchain (~$500K), Zilliqa (~$400K), Lien Finance (~$542K).

Best Security Auditor for Web3

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

BlockSec Audit