За прошедшую неделю (06.04.2026 - 12.04.2026) компания BlockSec зафиксировала и проанализировала четыре инцидента, связанных с атаками, общий оценочный ущерб от которых составил примерно $928,6 тыс. В таблице ниже представлены краткие сведения об этих инцидентах, а подробный анализ каждого случая приведен в следующих подразделах.
| Дата | Инцидент | Тип | Оценочный ущерб |
|---|---|---|---|
| 05.04.2026* | Инцидент с Denaria | Асимметрия округления и небезопасное приведение типов |
~$165,6 тыс. |
| 07.04.2026 | Инцидент с токеном HB | Ошибка бизнес-логики и манипуляция ценой |
~$193 тыс. |
| 07.04.2026 | Инцидент с Squid Multicall | Произвольные вызовы | ~$517 тыс. |
| 11.04.2026 | Инцидент с XBIT | Проблема контроля доступа | ~$53 тыс. |
*Инцидент с Denaria не был включен в отчет на прошлой неделе и добавлен сейчас для полноты картины.
Лучший аудитор безопасности для Web3
Проверьте дизайн, код и бизнес-логику перед запуском
Начиная с этой недели, мы выделяем один инцидент в начале каждого отчета. Выбор основывается не обязательно на сумме ущерба — он может быть сделан из-за необычного дизайна протокола, изощренной техники атаки или более широких уроков для сообщества.
Еженедельный обзор: Инцидент с Denaria
Бессрочный DEX Denaria представил новые механизмы учета, подкрепленные сложной логикой кода. Однако рефакторинг после аудита привел к асимметрии округления, что могло создать редкий граничный случай — отрицательное значение. В конечном итоге это привело к небезопасному приведению типов и позволило осуществить астрономический вывод средств.
5 апреля 2026 года бессрочный DEX Denaria в сети Linea подвергся атаке, повлекшей убытки на сумму около $165,6 тыс. Первопричиной стали две усугубляющие друг друга ошибки в функции getLpLiquidityBalance(): рефакторинг учета баланса LP после аудита внес асимметрию округления, которая могла приводить к небольшому отрицательному промежуточному значению, а небезопасное приведение типов (cast) из int256 в uint256 «тихо» преобразовывало это отрицательное число в почти максимальное целое число без знака вместо того, чтобы вызвать откат (revert). Атакующий воспользовался этим посредством одностороннего депозита LP и длинной позиции (long trade), а затем вывел искусственно завышенную прибыль из хранилища (vault).
Предыстория
Denaria — это бессрочный DEX на Linea, построенный на базе динамического виртуального AMM. Он разделяет торговлю и расчеты на два компонента. Рынок PerpPair управляет позициями пользователей и учетом LP, а Vault хранит обеспечение и производит расчеты реализованной прибыли/убытков (PnL).
Владение LP в PerpPair не представлено явным балансом токенов. Вместо этого протокол восстанавливает состояние каждого LP из матрицы внутреннего учета, состоящей из двух компонентов: стороны активов и стороны стабильных монет. Сторона активов отслеживает долю LP в подверженности пула колебаниям цен, а сторона стабильных монет — его долю в стоимости пула, номинированной в стейблкоинах. Вместе эти два компонента определяют, как отслеживается и рассчитывается стоимость активов LP.
Важно отметить, что эти компоненты не хранятся в виде статических снимков. Каждый раз, когда происходит сделка, PerpPair обновляет свое глобальное ликвидное состояние, и восстановленный баланс каждого LP вычисляется как разница между совокупными глобальными значениями и снимком точки входа LP. Этот механизм учета был введен в ходе рефакторинга после аудита, который заменил оригинальный накопитель на основе долей на прямое отслеживание баланса. Однако путь вычитания в рефакторинге внес асимметрию округления, которая могла привести к тому, что восстановленные компоненты LP становились слегка отрицательными при определенных последовательностях сделок.
Анализ уязвимости
Уязвимый контракт PerpPair (0xb683...36ae17) содержит две усугубляющие ошибки.
- Асимметрия округления в рефакторизованном учете. Рефакторинг после аудита, который внедрил прямое отслеживание баланса, создал асимметрию округления в пути реконструкции вычитанием. При определенных последовательностях сделок глобальное совокупное значение после округления могло стать незначительно меньше, чем снимок точки входа LP, из-за чего вычитание давало небольшой отрицательный результат вместо нуля. Теоретически это значение должно было быть нулевым или близким к нулю; асимметрия была ошибкой, специфичной для этой реализации, а не встроенным свойством вычитающего учета в целом.

- Небезопасное приведение типов (signed-to-unsigned cast). В функции
getLpLiquidityBalance()восстановленный компонент баланса LP приводился из типаint256кuint256без проверки. В Solidity приведение отрицательногоint256кuint256не вызывает откат; значение преобразуется по модулю 2^256, превращая небольшое отрицательное число, например -1, в почти максимальное целое число без знака (2^256 - 1). Поскольку этот восстановленный баланс подавался вcalcPnL()для расчетов, любой отрицательный вход интерпретировался как огромная позиция LP, позволяя атакующему реализовать фиктивно завышенную прибыль и опустошить хранилище.


Ни одна из этих ошибок по отдельности не была бы эксплуатируемой. Асимметрия округления приводила лишь к слегка отрицательному значению, которое при обычной арифметике int256 представляло бы собой незначительную погрешность. Но как только это отрицательное значение попадало в незащищенное приведение типа, оно превращалось в почти максимальное целое число. Последующая проверка границ ограничивала это значение общей ликвидностью пула по стороне активов, по сути преобразуя переполнение в претензию на всю сторону активов рынка.
Анализ атаки
Следующий анализ основан на транзакции атаки 0xcb0744...0c606447.
-
Шаг 1: Атакующий взял флэш-кредит на
60 000USDCчерез Aave. -
Шаг 2: Вспомогательный адрес внес
30 000USDCв качестве обеспечения и добавил позицию LP только в стейблкоинах в размере19 980токенов. Внося средства только на стабильную сторону, вспомогательный адрес гарантировал, что его LP-компонент по стороне активов начинался с нуля, что делало его более подверженным уходу в отрицательную область из-за округления. -
Шаг 3: Второй вспомогательный адрес внес
15 000USDCи открыл длинную позицию номиналом100 000, что вызвало обновлениеliquidityM, приведшее к ключевой ошибке округления. Большой размер номинала относительно ликвидности пула усилил влияние округления на сделку, опустив восстановленный баланс активов первого вспомогательного адреса чуть ниже нуля. -
Шаг 4: Затем первый вспомогательный адрес вызвал
realizePnL(). Во время реконструкции баланса LP отрицательныйlpAssetBalanceпревратился в почти максимальноеuint256. Это значение было ограничено общей ликвидностью рынка по стороне активов, что сгенерировало сильно завышенную прибыль. Фактически протокол «поверил», что LP владеет всеми активами рынка. -
Шаг 5: Атакующий вывел завышенную прибыль из хранилища.

Эта схема повторялась до тех пор, пока оставшаяся ликвидность хранилища не была исчерпана. После погашения флэш-кредита атакующий получил прибыль в размере около $165,6 тыс.
Заключение
Эта атака в конечном счете была вызвана отсутствием проверки границ при преобразовании знакового числа в беззнаковое. Решение очевидно: заменить прямое приведение на SafeCast.toUint256(), которое вызывает откат при отрицательном значении вместо его «заворачивания».
В более широком смысле, этот инцидент иллюстрирует риск рефакторинга кода после аудита, который проходит без внешнего контроля. Согласно официальному отчету об инциденте, асимметрия округления была внедрена после завершающего внешнего аудита, когда команда заменила оригинальный накопитель на прямое отслеживание баланса. Хотя рефакторинг решил проблему переполнения, он создал новый граничный случай, который не был замечен внутренним тестированием. При рефакторинге основной логики учета новые пути кода должны рассматриваться как критически важные для безопасности и проходить повторный аудит, особенно когда восстановленные значения напрямую влияют на расчеты прибыли или логику вывода средств.
Начните работу с Phalcon Explorer
Погрузитесь в детали транзакций для безопасных действий
Попробовать сейчас бесплатноИнцидент с токеном HB
7 апреля 2026 года токен HB, кастомный ERC-20 с встроенными хуками покупки/продажи в сети BNB Chain, был атакован, что привело к убыткам около $193 тыс. Первопричиной стала ошибочная логика расчета вознаграждений: при срабатывании вызывалась функция swapBack(), которая удаляла резервы HB напрямую из пары PancakeSwap, а затем вызывала sync() для переоценки пула. После того как атакующий выкупил большую часть HB из пары, последующее выполнение swapBack() еще больше сократило оставшуюся ликвидность и резко повысило спотовую цену. Затем атакующий продавал крошечные суммы HB в искаженный пул за непропорционально большие суммы USDT, повторяя цикл, пока пара не была опустошена.
Предыстория
HB — это кастомный токен стандарта ERC-20 в сети BNB Chain, имеющий хуки покупки и продажи в функции _transfer(). Когда пользователи покупают у AMM-пары, _handleBuy() записывает данные о базисе стоимости. При продаже _handleSell() перенаправляет логику в зависимости от состояния пары на разные пути налогообложения и расчетов.
В токен также включен механизм расчета вознаграждений, который может запускать swapBack(). Вместо совершения обычного свопа через маршрутизатор, swapBack() переводит HB напрямую из пары PancakeSwap на адрес PROOF, а затем принудительно синхронизирует пару через sync(). Это позволяет контракту сокращать резервы HB в паре вне обычных торговых потоков AMM и немедленно повышать цену актива.
Анализ уязвимости
Основная ошибка в контракте токена HB (0x62ce...87a4b0) заключалась в том, что swapBack() получал вознаграждения путем прямого изъятия токенов из AMM-пары, а не из казначейства или через своп с участием маршрутизатора. Поскольку swapBack() был доступен через путь расчета вознаграждений, неторговый путь кода мог напрямую менять резервы пары и искажать спотовую цену.

Когда резервы HB в паре низки, вызов swapBack() еще сильнее сокращает остаток HB и усиливает ценовое искажение, что позволяет продавать крошечные объемы HB по экстремально завышенным ценам.
Анализ атаки
Следующий анализ основан на транзакции атаки 0x19671f...d71594ed.
-
Шаг 1: Атакующий взял крупные суммы в долг в протоколе Venus.
-
Шаг 2: Атакующий перевел около
1 496HBна контракт токена, увеличив его баланс, чтобы последующий вызовswapBack()мог изъять из пары больше токенов. -
Шаг 3: Переведя крошечное количество
HBв пару PancakeSwap, атакующий запустил_swapAndLiquify(), который обменял примерно4 163HB, хранящихся на контракте токена, на10USDTи увеличил право атакующего на вознаграждение вHB.

- Шаг 4: Затем атакующий потратил
72 117 360USDTна покупку73 608 753HB, оставив в паре очень мало ликвидностиHB.

- Шаг 5: Далее атакующий инициировал путь расчета вознаграждений. Для покрытия вознаграждений токен вызвал
swapBack(), который изъял дополнительныеHBиз пары PancakeSwap и принудительно вызвалsync(), резко взвинтив ценуHB.

- Шаг 6: Атакующий напрямую перевел
USDTв пару, чтобы восполнить резервыUSDT, а затем продал всего0,000582HBза37 582 322USDTпо искаженной цене.
Повторяя шаг 6 и продавая токены HB по искаженной цене, атакующий вывел из пула почти все USDT.
Заключение
Инцидент с токеном HB показывает, насколько опасно позволять логике вознаграждений напрямую изменять резервы AMM. Функции, влияющие на резервы, никогда не должны быть доступны из путей расчета вознаграждений, а протоколы должны избегать смешивания внутренних балансов токена с учетом резервов AMM в критических для безопасности участках кода. Любой дизайн, полагающийся на спотовую цену AMM после внутреннего вмешательства в пул, изначально уязвим к манипуляциям ценой.
Инцидент с Squid Multicall
7 апреля 2026 года пользователь Squid потерял около $517 тыс. в разных сетях из-за инцидента, связанного с разрешением (approval). Пользователь по ошибке предоставил разрешение (approve) контракту SquidMulticall вместо предназначенного для этого Squid Router. Это позволило атакующему вызвать не имеющую прав доступа функцию SquidMulticall.run() для выполнения произвольных внешних вызовов. Таким образом, атакующий смог использовать любые права, делегированные контракту, для совершения вызовов transferFrom() против пользователей, предоставивших ему такое разрешение.
Предыстория
В стандартном рабочем процессе Squid пользователи должны предоставлять разрешение Squid Router, в то время как SquidMulticall выступает только как вспомогательный контракт для исполнения. Вспомогательный контракт предназначен для выполнения пакетных вызовов в рамках логики маршрутизации, но он не должен быть тем контрактом-получателем (spender), которому пользователи напрямую дают доступ к токенам.
Поскольку проверки лимитов (allowance) стандарта ERC-20 выполняются только для адреса получателя, любой контракт, который сочетает пользовательские разрешения с возможностью совершения произвольных вызовов без ограничений, создает опасную «черную дыру»: после одобрения контракт становится вектором для вывода токенов, если кто-то может контролировать, какие именно вызовы он совершает.
Анализ уязвимости
Этот инцидент был вызван не уязвимостью в смарт-контракте. Убытки стали результатом сочетания двух факторов: ошибочного одобрения контракта SquidMulticall вместо маршрутизатора и отсутствия ограничений доступа в функции run(), которая принимает произвольные цели и calldata от любого вызывающего.
SquidMulticall задуман для выполнения пакетных вызовов как конечный этап потока в маршрутизаторе, где входные данные формируются доверенной логикой. При использовании по назначению этот дизайн без ограничений не несет риска. Но ошибочное одобрение полностью меняет ситуацию: MEV-бот обнаружил действующее разрешение, вызвал run() со специально сформированными calldata для совершения transferFrom(victim, attacker, amount) и вывел разрешенные токены во всех сетях без каких-либо дальнейших действий со стороны жертвы.

Анализ атаки
Инцидент затронул пользователя в сетях BNB Chain, Arbitrum, Optimism, Avalanche и Base. Анализ основан на транзакции 0x81d0c4...9b1301e9.
-
Шаг 1: Жертва (0xacc0...f40e98) по ошибке дала одобрение
SquidMulticallвместо нужного Squid Router. -
Шаг 2: MEV-бот обнаружил этот лимит и вызвал
SquidMulticall.run()с подготовленными calldata. -
Шаг 3: Через произвольный вызов
SquidMulticallинициировалtransferFrom(victim, attacker, amount)и перевел доступные активы с кошелька жертвы.

Заключение
Этот инцидент иллюстрирует опасность сосуществования контрактов для произвольных вызовов без ограничений доступа с рабочими процессами одобрения пользовательских транзакций. Непосредственной причиной стала ошибка пользователя, но так как SquidMulticall принимал вызовы от кого угодно и позволял совершать любые операции, любое ошибочное одобрение мгновенно становилось эксплуатируемым. Протоколы, использующие вспомогательные контракты для выполнения задач, должны вводить ограничения на того, кто может вызывать функции, или на допустимые цели вызовов, чтобы ошибочное одобрение не превращалось в инструмент кражи.
Инцидент с XBIT
11 апреля 2026 года токен XBIT в сети BNB Chain был атакован, что привело к убыткам около $53 тыс. Первопричиной стала ошибка открытого контроля доступа (fail-open access control) в контракте XBITVault: проверка авторизации в функции transfer() была условной — она требовала msg.sender == xbitContract только если xbitContract был не нулевым, и молча пропускала вызов в противном случае. Поскольку функция bindXBIT() для инициализации контракта никогда не вызывалась, эта уязвимость была доступна постоянно, позволяя любому внешнему вызывающему перемещать балансы XBIT с любого адреса, включая пару PancakeSwap XBIT/USDT. Атакующий использовал это для изъятия XBIT из пары, а затем постоянно продавал крошечные суммы XBIT обратно в пул за непропорционально крупные суммы USDT.
Предыстория
XBITVault — это не пассивный казначейский контракт, а внутренний бэкенд для системы токенов XBIT, предоставляющий функции вроде transfer(), approve() и mintForXBIT(). По замыслу владельцы должны сначала вызвать bindXBIT() для инициализации хранилища, установив xbitContract, pancakePair, pairContract и xbitDecimals. После инициализации функции, меняющие состояние, должны быть доступны только для привязанного контракта XBIT. Другими словами, модель безопасности хранилища зависит от успешной инициализации перед публичным использованием.
Анализ уязвимости
Критическая ошибка заключается в условности контроля доступа в уязвимом контракте XBITVault (0xc879...42391a). Функция transfer() проверяет соответствие msg.sender == xbitContract только когда xbitContract != address(0). Это означает, что функция не вызывает откат, когда адрес не задан, и вместо этого становится публично доступной для всех. Поскольку балансы хранятся в _balances, любой внешний пользователь может переместить XBIT с любого адреса на любой другой, при условии, что исходный адрес имеет достаточный баланс.

Планируемым путем инициализации был bindXBIT(), но из-за того, что он не был вызван, хранилище оставалось в неинициализированном состоянии с «открытой» защитой. По сути, это предоставило возможность произвольного перевода балансов любому желающему.

Анализ атаки
Следующий анализ основан на транзакции атаки 0xbc877f...4df1b694.
-
Шаг 1: Через функцию
transfer()без ограничения доступа атакующий вывел1 526 216,569XBITиз парыXBIT/USDT, не предоставив взаменUSDT. -
Шаг 2: Атакующий вызвал
sync()для сжатия резервовXBITв паре до всего 1-2 единиц. -
Шаг 3: После того как в паре почти исчезла ликвидность
XBIT, атакующий неоднократно продавалXBIT, выкачивая около53 112USDTиз пары.

Заключение
Этот инцидент был вызван проверкой доступа, зависящей от инициализации, которая работала по принципу «безопасность по умолчанию отключена» (fail-open). Функция transfer() была доступна всем, пока xbitContract был не задан, а из-за того, что bindXBIT() никогда не вызывалась, хранилище на постоянной основе предоставляло публичный примитив для произвольного перевода балансов. Привилегированные функции должны блокировать вызовы до завершения инициализации, а шаги по привязке параметров при развертывании должны быть обязательными требованиями в блокчейне, а не просто операционными допущениями.
О компании BlockSec
BlockSec — это полноценный провайдер услуг в сфере безопасности блокчейнов и крипто-комплаенса. Мы создаем продукты и сервисы, которые помогают клиентам проводить аудит кода (включая смарт-контракты, блокчейны и кошельки), перехватывать атаки в режиме реального времени, анализировать инциденты, отслеживать незаконные средства и соблюдать обязательства AML/CFT на протяжении всего жизненного цикла протоколов и платформ.
BlockSec опубликовала множество статей по безопасности блокчейнов на престижных конференциях, сообщила о нескольких уязвимостях нулевого дня в DeFi-приложениях, заблокировала многочисленные хакерские атаки, спасла более 20 миллионов долларов и обеспечила безопасность криптовалют на миллиарды долларов.
-
Официальный сайт: https://blocksec.com/
-
Официальный Twitter: https://twitter.com/BlockSecTeam



