Back to Blog

Еженедельный обзор инцидентов безопасности Web3 | 13–19 апр. 2026

Code Auditing
April 22, 2026
18 min read
Key Insights

За прошедшую неделю (2026/04/13 - 2026/04/19) BlockSec обнаружила и проанализировала четыре инцидента с атаками, общий оценочный ущерб от которых составил приблизительно $310M. В таблице ниже представлена сводка этих инцидентов, а подробный анализ каждого случая приведён в соответствующих подразделах.

Дата Инцидент Тип Оценочный ущерб
2026/04/18 KelpDAO Компрометация инфраструктуры $290M
2026/04/16 Rhea Finance Некорректный учёт $18.4M
2026/04/13 Hyperbridge Ненадлежащая валидация $242K
2026/04/13 Dango Ненадлежащая валидация $1.5M

Лучший аудитор безопасности для Web3

Проверьте дизайн, код и бизнес-логику до запуска

Главное событие недели: KelpDAO

Подробный отчёт о каскадных последствиях эксплойта, механизме восстановления on-chain Arbitrum и более широких последствиях для управления см. по ссылке: Дилемма децентрализации: каскадные риски и экстренные полномочия в кризисе KelpDAO

Этот инцидент выделяется в силу нового вектора атаки на уровне инфраструктуры (отравление RPC единственного DVN вместо эксплуатации смарт-контракта), его каскадного воздействия на несколько цепочек через компонуемость DeFi, а также вопросов управления, поднятых принудительным переходом состояния Arbitrum для возврата похищенных средств.

18 апреля 2026 года OFT-мост rsETH LayerZero от KelpDAO был атакован приблизительно на $290M в ходе атаки, приписываемой спонсируемому государством субъекту, предположительно группировке Lazarus из КНДР [1]. Первопричиной стала конфигурация DVN 1-of-1 в KelpDAO, которая свела верификацию кросс-чейн сообщений к единой точке отказа. Злоумышленник отравил RPC-инфраструктуру, которой доверял DVN LayerZero Labs, вынудив его подтвердить поддельное кросс-чейн сообщение, в результате чего на Ethereum было выпущено 116 500 rsETH без каких-либо соответствующих событий на стороне источника в Unichain.

Предыстория

LayerZero — это протокол кросс-чейн обмена сообщениями, построенный на модульной архитектуре безопасности. В его основе целостность кросс-чейн сообщений обеспечивается децентрализованными сетями верификаторов (DVN) — внецепочечными субъектами, ответственными за независимую проверку того, что сообщение, отправленное в исходной цепочке, действительно имело место, прежде чем оно будет исполнено в целевой цепочке. Каждое приложение, развёртываемое на LayerZero, самостоятельно настраивает свою конфигурацию DVN: каким DVN доверять, сколько из них требуется и какой порог консенсуса должен быть достигнут. Эта модульность даёт приложениям полный контроль над своей моделью безопасности, но и полную ответственность: слабую конфигурацию нельзя подстраховать на уровне протокола.

rsETH KelpDAO развёрнут как OFT (Omnichain Fungible Token) на LayerZero с маршрутом моста, соединяющим Unichain (источник) и Ethereum mainnet (назначение). Стандарт OFT позволяет сжигать токены в исходной цепочке и высвобождать их из блокировки в целевой цепочке, при этом кросс-чейн сообщение служит единственным авторизационным документом для высвобождения. Адаптер на стороне Ethereum (0x85d456...e98ef3) отвечает за выпуск rsETH получателям после того, как действительное кросс-чейн сообщение было верифицировано и доставлено. Принципиально важно, что KelpDAO настроил этот маршрут с конфигурацией DVN 1-of-1, назначив LayerZero Labs единственным верификатором. Это означало, что для авторизации любого выпуска токенов достаточно было одного подтверждения DVN без необходимости второго мнения.

Для выполнения своих обязанностей по верификации DVN LayerZero Labs запрашивает несколько RPC-узлов, чтобы убедиться в том, что событие кросс-чейн отправки действительно произошло в исходной цепочке. Эти RPC-узлы включают как собственную инфраструктуру, так и внешних провайдеров, и DVN опирается на их совокупные ответы перед подписанием подтверждения. Целостность этого процесса зависит от допущения о том, что большинство опрашиваемых узлов возвращают достоверные данные.

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

Уязвимость представляет собой системный сбой на уровне инфраструктуры и конфигурации, состоящий из трёх взаимоусиливающих слабостей.

Во-первых, конфигурация DVN 1-of-1 в KelpDAO устранила всякую избыточность на уровне верификации. Рекомендованный уровень безопасности LayerZero явно требует многоузловых конфигураций DVN с независимыми верификаторами, при которых ни один DVN не может в одностороннем порядке авторизовать сообщение. Опираясь исключительно на DVN LayerZero Labs, KelpDAO создал условие, при котором любой компрометации этого единственного верификатора было бы достаточно для авторизации произвольного выпуска токенов.

Во-вторых, механизм переключения при отказе DVN направляет запросы верификации к тем RPC-узлам, которые остаются доступными. Этот дизайн предполагает, что недоступность узла носит случайный, а не преднамеренный характер. Однако он создаёт условие, при котором злоумышленнику не нужно компрометировать все источники данных: выведя работоспособные узлы из строя с помощью DDoS и заблаговременно подготовив отравленные узлы как единственную доступную альтернативу, атакующий получает полный контроль над данными, которые получает DVN.

В-третьих, замена исполняемого файла op-geth на RPC-узлах требовала доступа на уровне ОС к базовым серверам. Точный вектор первоначального доступа не был раскрыт, однако компрометация двух независимых узлов на отдельных кластерах может указывать на общую слабость в том, как управлялся доступ к этим серверам.

В совокупности эти три условия сформировали полную цепочку атаки: первое обеспечило отсутствие независимого DVN для перекрёстной проверки подтверждённого сообщения; второе гарантировало злоумышленнику полный контроль над данными, которые получает единственный DVN; третье обеспечило первоначальный плацдарм, сделавший возможной манипуляцию данными. Ни одной из этих слабостей в отдельности не было бы достаточно. Без конфигурации 1-of-1 второй DVN, запрашивающий независимую инфраструктуру, отверг бы поддельное сообщение. Без поведения переключения при отказе работоспособные узлы перевесили бы отравленные. Без компрометации серверов у злоумышленника не было бы возможности внедрить поддельные данные.

Анализ атаки

Следующий анализ основан на транзакции 0x1ae232...4222 и официальном заявлении об инциденте от LayerZero Labs.

  • Шаг 1: Злоумышленник получил список конкретных RPC-узлов, которым доверял DVN LayerZero Labs. Этот список представлял собой высокоценную разведывательную цель, поскольку знание точных узлов позволяло злоумышленнику спланировать хирургическую операцию, а не широкомасштабную атаку на инфраструктуру.

  • Шаг 2: Злоумышленник получил доступ для записи на уровне ОС к двум из RPC-узлов и заменил работающие бинарные файлы op-geth вредоносными версиями. Эти два узла, по имеющимся данным, работали на независимых кластерах без прямого соединения друг с другом, что указывает на то, что вектор первоначального доступа был связан с общей зависимостью на более высоком уровне (например, скомпрометированные учётные данные развёртывания, конвейер CI/CD или социальная инженерия оператора с доступом к обоим). Точный метод первоначального доступа не был раскрыт LayerZero Labs. Этот шаг являлся предпосылкой для всех последующих манипуляций с данными.

  • Шаг 3: Вредоносный бинарный файл op-geth реализовал целевую логику ответов: он возвращал поддельные данные транзакций исключительно на IP-адрес DVN, одновременно предоставляя достоверное состояние блокчейна всем остальным запрашивающим, включая собственную инфраструктуру мониторинга LayerZero, обозреватели блоков и сервисы сканирования. Это избирательное отравление сделало атаку невидимой для всех существующих систем наблюдаемости: с любой внешней точки зрения исходная цепочка выглядела нормально.

  • Шаг 4: Внутренний консенсус DVN требовал согласования между отравленными и неповреждёнными RPC-узлами. Для разрешения этого противоречия злоумышленник провёл DDoS-атаку на оставшиеся работоспособные узлы в течение окна атаки (10:20–11:40 AM PT), активировав логику переключения DVN при отказе и вынудив его опираться исключительно на отравленную инфраструктуру. Этот шаг был необходим, поскольку в противном случае работоспособные узлы вернули бы достоверные данные, противоречащие поддельным ответам.

  • Шаг 5: Когда DVN начал получать только данные, контролируемые злоумышленником, поддельное кросс-чейн сообщение LayerZero было представлено как действительное. DVN подтвердил нонс 308 на конечной точке назначения Ethereum — нонс, которому не соответствовало ни одного исходящего события в Unichain (что подтверждается тем, что конечная точка источника по-прежнему сообщала о максимальном исходящем нонсе 307).

  • Шаг 6: Адаптер rsETH на стороне Ethereum, получив надлежащим образом подтверждённое сообщение, выпустил 116 500 rsETH на адрес получателя злоумышленника (0x8b1b6c...0d3b), который был предварительно пополнен через Tornado Cash за несколько часов до атаки. Похищенные токены были немедленно распределены по семи дочерним кошелькам и ликвидированы через залоговые позиции Aave, прямые свопы ETH и перемещение через мост на Arbitrum; конечные поступления сконцентрировались на адресе 0x5d3919...7ccc на Ethereum и соответствующем адресе-коллекторе на Arbitrum.

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

  • Шаг 8: Последующая попытка злоумышленника воспользоваться тем же маршрутом для дополнительного получения 40 000 rsETH (~$95M) была заблокирована после того, как KelpDAO обнаружила аномалию и приостановила все соответствующие контракты на Ethereum mainnet и L2 [2].

Более широкие последствия

Ущерб значительно превысил первоначальный эксплойт моста на $290M. Злоумышленник внёс около 89 567 rsETH (~$221M) в Aave на нескольких рынках, занимая WETH при LTV 93% в режиме E-Mode [4]. Поскольку Aave не мог отличить легально перемещённый rsETH от токенов, выпущенных по поддельному сообщению, «отравленный» залог считался полностью действительным. Возникшая заморозка резерва WETH распространилась на Ethereum, Arbitrum, Base, Mantle и Linea, затронув пользователей, которые не имели никакого отношения к rsETH. Это каскадное распространение — от одного изъяна в конфигурации моста до сбоя на кредитных рынках нескольких цепочек — наглядно демонстрирует, как компонуемость DeFi усиливает как охват, так и стоимость единственной точки отказа.

Последствия инцидента поставили не менее важные вопросы об операционной реальности децентрализации. LayerZero Labs объявила, что её DVN больше не будет подписывать сообщения для приложений, использующих конфигурации 1-of-1 [1], что подразумевает: децентрализация на уровне протокола сама по себе не может компенсировать слабости конфигурации на уровне приложений.

На уровне цепочки Арбитражный совет безопасности выполнил экстренное действие по заморозке 30 766 ETH, удерживаемых злоумышленником на Arbitrum One. Как проанализировано BlockSec [5], это было достигнуто посредством принудительного перехода состояния на уровне цепочки: Совет безопасности временно обновил контракт входящих сообщений Ethereum, внедрил неподписанное сообщение L1-to-L2, имитирующее адрес злоумышленника, и восстановил исходную реализацию — всё это без необходимости подписи держателя [3].

Это действие представляло собой законное осуществление экстренных полномочий, определённых в системе управления, проведённое открыто и в координации с правоохранительными органами. Тем не менее оно также демонстрирует, что цепочки L2 по своей конструкции сохраняют возможности централизованного вмешательства: любой актив на Arbitrum One в принципе может быть перемещён Советом безопасности с помощью того же механизма. Разрыв между теоретической моделью доверия системы и её реальной границей доверия — как показывает этот инцидент на каждом уровне — является местом, где сосредоточены наиболее значимые риски.

Заключение

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

Три меры по отдельности предотвратили бы этот исход:

  • Конфигурация с несколькими DVN: требование консенсуса между несколькими независимыми DVN сделало бы компрометацию одного DVN недостаточной для авторизации сообщения, независимо от того, насколько полно этот DVN был введён в заблуждение.

  • Выбор RPC с учётом переключения при отказе: резкое падение количества доступных узлов в ходе активного окна верификации следует рассматривать как потенциальный сигнал атаки, а не как рядовое событие нарушения доступности. Реализации DVN должны прекращать работу или генерировать предупреждение, а не продолжать работу с уменьшенным набором узлов.

  • Укрепление инфраструктуры RPC: возможность заменить работающий исполняемый файл на производственном RPC-узле свидетельствует о недостаточном контроле доступа к базовым серверам. Инфраструктура, на которую опираются DVN для получения достоверных данных из исходной цепочки, должна быть защищена тем же периметром безопасности, что и сами экземпляры подписания DVN.

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

Ссылки

[1] LayerZero Labs, «Заявление об инциденте KelpDAO», 20 апреля 2026 г. https://x.com/LayerZero_Core/status/2046081551574983137

[2] KelpDAO, «Инцидент 18 апреля: дополнительный контекст», 21 апреля 2026 г. https://x.com/KelpDAO/status/2046332070277091807

[3] Arbitrum, «Экстренное действие Совета безопасности», 21 апреля 2026 г. https://x.com/arbitrum/status/2046435443680346189

[4] LlamaRisk, «Отчёт об инциденте с rsETH», 20 апреля 2026 г. https://governance.aave.com/t/rseth-incident-report-april-20-2026/24580

[5] BlockSec, «Анализ механизма заморозки Советом безопасности Arbitrum», 21 апреля 2026 г. https://x.com/Phalcon_xyz/status/2046467830498173088

Начните работу с Phalcon Explorer

Погрузитесь в транзакции, чтобы действовать разумно

Попробуйте бесплатно

Другие инциденты недели


Rhea Finance

16 апреля 2026 года Burrowland — протокол кредитования и маржинальной торговли на NEAR под управлением Rhea Finance — был атакован приблизительно на $18.4M из-за логической ошибки в бизнес-логике модуля маржинальной торговли. При открытии позиции с кредитным плечом протокол использует verify_token_out() для проверки ожидаемого результата свопа перед принятием позиции. Однако эта функция некорректно накапливала суммы token_out из промежуточных шагов свопа, когда токен совпадал с итоговым выходным токеном, не учитывая, что эти промежуточные суммы впоследствии повторно использовались в качестве token_in. Злоумышленник развернул поддельные токены и пулы, а затем сконструировал круговой маршрут свопа, который искусственно завысил воспринимаемую выходную сумму и прошёл проверки платёжеспособности, опустошив протокол приблизительно на $18.4M.

Предыстория

Burrowland — это протокол кредитования и маржинальной торговли с открытым исходным кодом на NEAR. Помимо стандартных функций предложения и заимствования, он поддерживает маржинальную торговлю и вводит три ключевые переменные для представления позиции пользователя с кредитным плечом: token_c (залог), token_d (заёмный актив) и token_p (позиционный актив).

При длинной позиции пользователь вносит token_c в качестве залога и занимает token_d с выбранным кредитным плечом (например, 5x). Затем заимствованный token_d обменивается на DEX на token_p — актив, к которому пользователь хочет получить экспозицию. В нормальных условиях стоимость полученного token_p приблизительно равна стоимости потраченного token_d. Протокол удерживает token_p от имени пользователя, одновременно фиксируя заимствованный token_d в качестве долга.

При короткой позиции пользователь аналогично вносит token_c и занимает token_d (актив, на который хочет открыть шорт) с кредитным плечом. Заимствованный token_d обменивается на другой актив (token_p), что фактически создаёт короткую экспозицию к token_d. В этом случае также ожидается, что своп сохранит стоимость при нормальных рыночных условиях.

На протяжении всего жизненного цикла позиции token_p остаётся под хранением протокола, и пользователь не может напрямую его вывести. Для фиксации прибыли или убытка позиция должна быть закрыта, после чего token_p обменивается обратно на token_d для погашения долга.

Открытие маржинальной позиции обрабатывается функцией internal_margin_open_position(), которая устанавливает параметры позиции и направляет заимствование на DEX.

Перед принятием новой позиции протокол последовательно оценивает четыре уровня защиты: is_min_amount_out_reasonable() перекрёстно проверяет задекларированное пользователем min_token_p_amount относительно ожидаемого результата свопа по оракулу Pyth для ограничения проскальзывания; is_open_position_liquidatable() проверяет, что ожидаемая стоимость позиции и залога не опускается ниже порога ликвидации; is_open_position_forcecloseable() проверяет, что счёт не является уже неплатёжеспособным номинально; get_open_position_lr() обеспечивает соответствие соотношения стоимости token_d / token_c максимально допустимому коэффициенту кредитного плеча.

Все четыре проверки используют min_token_p_amount в качестве стоимости позиционного актива, поскольку своп ещё не выполнен и нет фактической реализованной суммы. Корректность каждого уровня защиты поэтому полностью зависит от того, ограничено ли min_token_p_amount тем, что DEX реально предоставит. Именно это ограничение должна обеспечивать функция verify_token_out(), реализованная через RefV1TokenReceiverMessage::get_token_out(), для сообщения о свопе, предоставляемого пользователем.

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

Ошибка находится внутри функции verify_token_out(). Функция берёт token_out последнего шага свопа в качестве итогового выходного токена, а затем суммирует задекларированный min_amount_out каждого шага свопа, производящего тот же токен, исходя из допущения, что каждое такое производство вносит вклад в итоговый результат. Это корректно для подлинного многопутевого (split-route) свопа, однако логика не исключает шаги, чей token_out немедленно потребляется в качестве token_in следующего шага. Круговой маршрут вида A->B->A->B приводит к тому, что каждый шаг ->B учитывается в сумме, даже несмотря на то, что его результат расходуется на следующем шаге B->A и никогда не поступает в Burrowland. Суммарный min_amount_out, одобряемый функцией verify_token_out(), более не отражает то, что DEX фактически вернёт.

После обхода verify_token_out() завышенный min_token_p_amount принимается как истина на протяжении всего выполнения internal_margin_open_position(). Каждый уровень проверки платёжеспособности, призванный остановить небезопасное открытие, вычисляется на основе сфабрикованного числа, поэтому позиция принимается и протокол направляет заимствованный token_d на DEX с приложенным круговым сообщением о свопе.

Анализ атаки

Следующий анализ основан на транзакции GcXEKm...fnFT.

Фаза 1: Развёртывание поддельных токенов и пулов

Злоумышленник развернул три поддельных токена и создал пять поддельных пулов.

  1. Идентификаторы поддельных токенов:

    1. Fake1: 31623e1d98275d2b0db4f50e102f6bf40877c1345e06e4ca6727f58c89564bb2

    2. Fake2: 6a28e3d3c7af1415ec22c6264013e1138bab00f85b8b6055d882d7d46afdf49b

    3. Fake3: e081e03daf58f5bb04cf95a03017e58449b76e704f1974771d7e3bd52835b6e5

  2. Идентификаторы поддельных пулов:

    1. Zec-Fake1: 7509

    2. Fake1-Fake2: 7510

    3. USDC-Fake2: 7511

    4. Fake2-Fake3: 7512

    5. Fake3-USDC: 7513

Фаза 2: Открытие маржинальной позиции

  • Шаг 1: Используя функцию маржинальной торговли Burrowland, злоумышленник открыл позицию с кредитным плечом, использовав легитимно ценный актив в качестве token_c и реальный резервный актив в качестве token_d, приложив сообщение о свопе, список действий которого представляет собой круговой маршрут A->B->A->B, полностью проходящий через контролируемые злоумышленником пулы из Фазы 1.
  • Шаг 2: Поскольку verify_token_out() суммирует min_amount_out по всем шагам, чей token_out совпадает с терминальным результатом, круговой маршрут позволил злоумышленнику искусственно завысить задекларированный min_token_p_amount до произвольного значения.

  • Шаг 3: Завышенный min_token_p_amount прошёл все проверки работоспособности при открытии в internal_margin_open_position(), поэтому позиция была принята и протокол направил token_d в Ref-Finance.

  • Шаг 4: Круговой своп вернул лишь пылевую сумму token_p; on_open_trade_return() зафиксировала её без какой-либо повторной проверки, в результате чего позиция стала неплатёжеспособной с момента создания.

  • Шаг 5: Заимствованный token_d осел в контролируемых злоумышленником пулах вдоль маршрута; злоумышленник извлёк его через remove_liquidity().

  • Шаг 6: Поскольку заимствование является заёмным с плечом, выведенный token_d стоит больше, чем внесённый token_c. Разница составляет чистую прибыль за цикл, а невзыскиваемый долг переходит в protocol_debts. Злоумышленник повторял схему до тех пор, пока не было опустошено около $18.4M.

Заключение

Этот инцидент был вызван ошибкой в бизнес-логике маршрута открытия маржинальной позиции в Burrowland. Функция RefV1TokenReceiverMessage::get_token_out() некорректно агрегировала промежуточные результаты, когда они совпадали с итоговым токеном, предполагая, что эти суммы останутся в качестве итогового результата. Однако круговые маршруты свопа нарушают это допущение, поскольку данные токены могут повторно использоваться и потребляться внутри маршрута. В результате вычисленный min_token_p_amount может быть искусственно завышен, что приводит к тому, что все последующие проверки платёжеспособности опираются на некорректное значение и позволяют открывать позиции при сфабрикованном состоянии работоспособности без проверки фактически полученной суммы.

Для контрактов маржинальной торговли в продуктивной среде разработчикам следует:

  • Рассматривать задекларированный пользователем min_amount_out как непроверенные входные данные и либо принимать только min_amount_out последнего шага, либо явно отклонять маршруты свопа, повторно потребляющие ранее произведённый token_out (без циклов через цель).

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

Начните работу с Phalcon Security

Обнаруживайте каждую угрозу, получайте важные оповещения и блокируйте атаки.

Попробуйте бесплатно

Hyperbridge

13 апреля 2026 года Hyperbridge — кросс-чейн мессенджинг-мост на Ethereum — был атакован приблизительно на $242K из-за отсутствия проверки входных данных в логике верификации доказательств MMR (Merkle Mountain Range). Функция MerkleMountainRange.VerifyProof() не проверяла выполнение условия leaf_index < leafCount, что позволило злоумышленнику сфабриковать кросс-чейн доказательство и совершить привилегированные действия, включая чеканку 1 000 000 000 токенов DOT.

Предыстория

Hyperbridge использует модель верификатора и диспетчера на стороне Ethereum для кросс-чейн сообщений. На Ethereum контракт HandlerV1 проверяет предоставленные доказательства относительно хранимого overlayRoot, и если доказательство принято, направляет сообщение к целевым модулям, таким как контракт TokenGateway.

Контракт TokenGateway — это привилегированный модуль управления активами. Помимо стандартного bridging активов, он также поддерживает действия в стиле управления, такие как создание активов, их исключение из реестра и управление администраторами. Для bridged-активов, реализованных как ERC6160Ext20, администратор может напрямую передавать право чеканки, вызывая функцию changeAdmin(), а новый администратор может затем выпускать произвольное количество токенов через функцию mint().

Это означает, что безопасность всего asset bridge зависит от корректности пути верификации доказательств в HandlerV1. Если поддельное сообщение может пройти верификацию, нижестоящие модули будут рассматривать полезные нагрузки, контролируемые злоумышленником, как подлинные кросс-чейн инструкции.

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

Основная проблема находится в потоке верификации доказательств MMR в контракте HandlerV1 (0x6c84ed...6d64). Входная функция handlePostRequests() сначала строит MmrLeaf(leaf.kIndex, leaf.index, commitment) на основе входных данных, предоставленных злоумышленником. Затем вызывается MerkleMountainRange.VerifyProof() для выполнения верификации доказательства.

MerkleMountainRange.VerifyProof(root, request.proof.multiproof, leaves, request.proof.leafCount)

Однако VerifyProof() проверяет только root == CalculateRoot(proof, leaves, mmrSize) и не проверяет, что каждый leaf.index находится в допустимом диапазоне (т.е. leaf.index < leafCount). Выбрав leafCount = 1 и leaf_index = 1, злоумышленник заставляет CalculateRoot() пропустить включение поддельного обязательства запроса в вычисленный корень, возвращая пиковый корень напрямую. Это нарушает привязку сообщения к доказательству и позволяет произвольным полезным нагрузкам проходить верификацию как действительные относительно исторического overlayRoot.

Анализ атаки

Следующий анализ основан на транзакции 0x240aeb...1109 [1].

  • Шаг 1: EOA злоумышленника 0xC513...F8E7 развернул вспомогательные контракты 0x518A...8f26 и 0x31a1...ca9AB в той же транзакции.

  • Шаг 2: Вспомогательный контракт 0x31a1...ca9AB отправил поддельный запрос через уязвимый путь верификации в HandlerV1. Поскольку VerifyProof() не отклонил выходящий за пределы диапазона leaf_index, обязательство поддельного запроса было исключено из вычисления корня, однако доказательство по-прежнему совпало с историческим overlayRoot.

  • Шаг 3: После принятия поддельного сообщения HandlerV1 перенаправил его в TokenGateway, выполнив действие ChangeAssetAdmin. Это изменило администратора токена DOT на контролируемый злоумышленником вспомогательный контракт 0x31a1...ca9AB.

  • Шаг 4: Вспомогательный контракт выпустил 1 000 000 000e18 токенов DOT.

  • Шаг 5: Вспомогательный контракт обменял только что выпущенные токены DOT на 108.2 ETH через Odos Router V3.

  • Шаг 6: Злоумышленник перевёл 108.2 ETH на свой EOA-счёт.

Заключение

Этот инцидент был вызван ненадлежащей валидацией доказательств в логике верификации MMR Hyperbridge. Поскольку условие leaf_index < leafCount не проверялось, злоумышленник смог сфабриковать сообщение, чьё обязательство фактически никогда не было включено в вычисленный корень, однако всё равно прошло верификацию относительно исторического корня состояния. Меры по устранению уязвимости должны включать строгие проверки границ, такие как leaf_index < leafCount, перед верификацией доказательства.

Ссылки

[1] BlockSec, «Анализ атаки на Hyperbridge», 13 апреля 2026 г. https://x.com/Phalcon_xyz/status/2043601549893738970


Dango

13 апреля 2026 года Dango — DEX бессрочных фьючерсов, построенный как Cosmos AppChain, — был атакован приблизительно на $1.5M из-за отсутствия проверки знака. Функция replenish_insurance_fund() использовала is_non_zero() вместо is_positive() для проверки входной суммы, что позволило злоумышленнику передать отрицательное значение UsdValue и опустошить страховой фонд в свою маржинальную позицию.

Предыстория

Dango — это DEX бессрочных фьючерсов, построенный как Cosmos AppChain. Пользователи вносят USDC в качестве залога в контракт perps и открывают позиции с кредитным плечом длинные или короткие на такие активы, как BTC, ETH и SOL, через on-chain центральную книгу лимитных ордеров (CLOB). Баланс залога каждого пользователя отслеживается как маржинальный счёт внутри контракта perps.

Для защиты поставщиков ликвидности (LP) от потерь по безнадёжным долгам протокол поддерживает страховой фонд: резерв USDC, хранящийся внутри контракта perps, который покрывает любой дефицит, когда залога ликвидированной позиции недостаточно для полного погашения долга. Без него такие дефициты напрямую перекладывались бы на LP. Любой пользователь мог перечислить маржу со своего perp-счёта в страховой фонд.

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

Первопричина кроется в функции replenish_insurance_fund() контракта 0x90bc84...bea4f, которая не отклоняет отрицательные входные суммы. У функции есть два защитных условия, однако ни одно из них не останавливает отрицательное amount:

  1. ensure!(amount.is_non_zero()) проверяет, что сумма не равна нулю, но не проверяет, что она является положительной.
  2. ensure!(user_state.margin >= amount) проверяет, что у пользователя достаточно маржи, но любая положительная маржа удовлетворяет условию >= отрицательное_число.

После прохождения обоих условий функция выполняет user_state.margin.checked_sub_assign(amount) и state.insurance_fund.checked_add_assign(amount). Когда amount отрицательна, её вычитание увеличивает маржу пользователя, а её прибавление уменьшает страховой фонд, полностью обращая задуманный поток средств.

Анализ атаки

Транзакции:

ID Tx Действие Хэш транзакции
1 Эксплойт 5505BB...A901
2 Bridge 95AD18...00B6
3 Bridge 95B5D7...D9AD
4 Bridge 2DA851...90E6
5 Bridge 4B141D...1CD4
6 Bridge FD1BFF...2E4E
7 Bridge 641015...E126
8 Bridge 9B951D...2858

Фаза 1:

В Tx 1 злоумышленник выполнил следующие шаги для опустошения активов из страхового фонда Dango:

  • Шаг 1: Злоумышленник открыл маржинальную позицию, внеся 1e6 USDC. Это являлось предпосылкой для вызова replenish_insurance_fund().
  • Шаг 2: Злоумышленник вызвал replenish_insurance_fund() с отрицательным значением amount (т.е. -1500000). Из-за ненадлежащей валидации отрицательное amount было принято, что привело к опустошению активов из страхового фонда на маржинальную позицию злоумышленника.

  • Шаг 3: Злоумышленник вывел все активы с маржинальной позиции, получив $1 500 000 в USDC.

Фаза 2:

В Tx 2–8 злоумышленник вызвал transfer_remote() для перемещения похищенных активов через мост на Ethereum. В результате $410 000 в USDC было переведено на Ethereum.

Заключение

Суть этой атаки заключается в использовании знакового целочисленного типа в беззнаковом контексте без проверки знака. Тип UsdValue является знаковым по замыслу (PnL по perps может быть отрицательным), однако путь пополнения страхового фонда имеет смысл только для положительных взносов. Использование is_non_zero() вместо is_positive() оставило однословный пробел, который позволял любому вызывающему обратить направление потока средств, опустошая USDC из страхового фонда на собственную маржу. Злоумышленник выполнил всю атаку в одной транзакции (внести $1, опустошить $1.5M, вывести $1 500 001), а затем медленно выводил средства через мост. Ограничение скорости моста было единственным механизмом, ограничившим ущерб: без него все ~$1.5M были бы безвозвратно перемещены на Ethereum.


О BlockSec

BlockSec — это поставщик полного стека решений для безопасности блокчейна и соответствия требованиям в области криптовалют. Мы создаём продукты и услуги, которые помогают клиентам проводить аудит кода (включая смарт-контракты, блокчейн и кошельки), перехватывать атаки в режиме реального времени, анализировать инциденты, отслеживать незаконные средства и выполнять обязательства по ПОД/ФТ на протяжении всего жизненного цикла протоколов и платформ.

BlockSec опубликовала несколько научных работ по безопасности блокчейна на престижных конференциях, выявила несколько атак нулевого дня на DeFi-приложения, заблокировала несколько взломов, спасая более 20 миллионов долларов, и обеспечила безопасность активов на миллиарды криптовалют.

Best Security Auditor for Web3

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

BlockSec Audit