За прошедшую неделю (20.04.2026 — 26.04.2026) компания BlockSec обнаружила и проанализировала восемь инцидентов, связанных с хакерскими атаками. Общий ориентировочный ущерб составил ~$7,04 млн. В таблице ниже приведена сводка этих инцидентов, а подробный анализ каждого случая представлен в следующих подразделах.
| Дата | Инцидент | Тип | Ущерб (оценка) |
|---|---|---|---|
| 2026/04/19* | Контракт Custom Rebalancer | Arbitrary Call (Произвольный вызов) | ~$64K |
| 2026/04/20 | REVLoans (Juicebox) | Некорректная проверка | ~$50.7K |
| 2026/04/22 | Volo Vault / Navi | Компрометация ключа | ~$3.5M |
| 2026/04/22 | Kipseli Router | Некорректная проверка | ~$72.35K |
| 2026/04/23 | GiddyDefi | Неполная проверка подписи | ~$1.3M |
| 2026/04/25 | Purrlend | Компрометация ключа | ~$1.5M |
| 2026/04/26 | SingularityFinance | Неверная настройка оракула | ~$413K |
| 2026/04/26 | Scallop | Ошибка учета | ~$142.7K |
*Инцидент с кастомным контрактом ребалансировки не был освещен в отчете на прошлой неделе и включен сюда для полноты картины.
Начните работу с Phalcon Explorer
Изучайте транзакции, чтобы принимать взвешенные решения
Попробовать бесплатноГлавное событие недели: GiddyDefi
Злоумышленник не взламывал подпись, не использовал флэш-займы и не манипулировал ценами. Он просто повторно использовал легитимную подпись, заменив подписанные поля на данные своего контракта. «Использование вашей собственной подписи против вас» — это самое наглядное доказательство того, как частичное покрытие EIP-712 превращает валидную подпись в универсальный инструмент для несанкционированного доступа.
23 апреля 2026 года контракт GiddyVaultV3 в сети Ethereum подвергся атаке с ущербом примерно в $1,3 млн. Схема проверки подписи покрывала только SwapInfo.data, оставляя поля aggregator, fromToken, toToken и amount вне хеша EIP-712. Это позволило повторно использовать валидную подпись с подменой этих полей. Злоумышленник указал в качестве aggregator вредоносный контракт, а fromToken — LP-токен стратегии, что привело к выводу активов на сумму около $1,3 млн.
Предыстория
GiddyVaultV3 (0x5f0a...4318) — это хранилище (vault) для доходного фермерства, где пользователи вносят и выводят средства через deposit() и withdraw(). Каждая операция должна содержать структуру авторизации VaultAuth, подписанную бэкендом. Она включает EIP-712 подпись и массив SwapInfo[ ], описывающий маршруты обмена токенов. При выполнении обмена контракт вызывает GiddyLibraryV3.executeSwap(), который выполняет forceApprove для swap.fromToken, предоставляя разрешение swap.aggregator, а затем проводит обмен через aggregator.call(swap.data). Контракт стратегии управляет средствами в соответствии с настроенной логикой.
EIP-712 — это стандарт для подписи структурированных данных вне сети (off-chain): протокол, использующий подпись, воссоздает ту же структуру в блокчейне, хеширует её с заданной подписью домена (domain separator) и восстанавливает адрес подписавшего. Безопасность любого потока EIP-712 зависит от того, покрывает ли хеш каждое поле, влияющее на выполнение. В дизайне Giddy бэкенд подписывает VaultAuth, содержащий намерение пользователя и маршруты обмена. Функция _validateAuthorization() восстанавливает эту структуру перед тем, как стратегии будет разрешено перемещать средства.
Анализ уязвимости
Уязвимость кроется в функции _validateAuthorization() контракта GiddyVaultV3. При построении подписанной полезной нагрузки хешируется только поле data каждого SwapInfo; поля aggregator, fromToken, toToken и amount исключены из подписи. Это означает, что любой владелец валидной подписи может свободно подменять оставшиеся поля SwapInfo, при этом проверка подписи будет проходить успешно.
Каждое исключенное поле — это отдельный рычаг: aggregator становится и тем, кто тратит средства, и целью вызова через forceApprove и aggregator.call(swap.data); fromToken выбирает, какой актив стратегии будет одобрен; amount устанавливает потолок суммы; toToken лишь проходит проверку returnAmount > 0. Подписанные данные data не ограничивают ничего из этого, поскольку ни одна из этих целей внутри них не упоминается.

Анализ атаки
Приведенный ниже анализ основан на транзакции 0x5edb66...5482e5.
-
Шаг 1: Злоумышленник получил из блокчейна легитимную подпись
VaultAuth, авторизованную бэкендом, сохранив полеdataбез изменений. Поскольку каждый вызовdeposit()илиwithdraw()транслирует полную полезную нагрузкуVaultAuthв сеть, любая историческая транзакция стала бесплатным источником пригодной для использования подписи. Злоумышленнику потребовалась лишь та, чье полеdataподходило для запланированного вызова обмена. -
Шаг 2: Используя полученную подпись, злоумышленник оставил значения
signature,nonceиdataбез изменений, но подменил остальные поля.fromTokenбыл установлен на LP-токен, которым владел контракт стратегии (реальный актив), поэтомуforceApproveпредоставил разрешение на токен, принадлежащий протоколу.aggregatorбыл заменен на вредоносный контракт злоумышленника, поэтому и одобрение, и последующийaggregator.call()были направлены на код, контролируемый атакующим. Поскольку эти поля находились вне области проверки подписи,_validateAuthorization()приняла измененную структуру. Чтобы обойти финальную проверкуrequire(returnAmount > 0, "SWAP_NO_TOKENS_RECEIVED"), вредоносный агрегатор реализовал функцию минтинга (выпуска), которая возвращала протоколу поддельные токены. Это обеспечило успешное выполнение проверки без реального обмена.


- Шаг 3: Поскольку вредоносный агрегатор получил одобрение на предыдущем шаге, злоумышленник вызвал
transferFrom, чтобы переместить LP-токены хранилища напрямую во вредоносный агрегатор, завершив кражу. Этот шаг полностью находился вне защищенного пути выполнения протокола. К моменту возврата изexecuteSwap()разрешение уже было записано, а проверка баланса после вызова — пройдена, поэтому у протокола не было возможности вмешаться.

Заключение
Первопричиной этой атаки стала неполная проверка подписи EIP-712. Основные поля SwapInfo, напрямую управляющие движением средств, остались незащищенными, что позволило злоумышленнику подменить маршрут обмена и адрес агрегатора, предъявив при этом валидную подпись. Разработчикам, интегрирующим внешние агрегаторы, следует:
-
Убедиться, что подписи EIP-712 покрывают все поля, влияющие на исход выполнения, включая
aggregator,fromToken,toTokenиamount. -
Применять «белый список» (whitelist) агрегаторов, чтобы предотвратить вызовы непроверенных внешних контрактов.
-
Ограничивать
toTokenтолько ожидаемыми базовыми токенами, чтобы предотвратить обход проверок баланса с помощью фейковых активов.
В более широком смысле, EIP-712 в любой архитектуре «разрешение-затем-вызов» должен хешировать каждое поле, влияющее на итоговое состояние сети, а не только намерение пользователя. В ситуациях, когда бэкенд-подпись является единственным барьером между параметрами, вводимыми пользователем, и привилегированным действием контракта, каждый параметр, поступающий в это действие (цель вызова, актив, сумма, получатель), должен находиться внутри подписанной структуры. Отношение к полю data как к подмене идентификатора вызова — это категориальная ошибка: идентификатор вызова — это кортеж всех его параметров, и любой параметр, оставленный вне подписи, по определению контролируется тем, кто отправляет транзакцию.
Лучший аудитор безопасности для Web3
Проверьте дизайн, код и бизнес-логику перед запуском
Другие инциденты этой недели
Контракт Custom Rebalancer
19 апреля 2026 года контракт ребалансировки sAVAX в сети Avalanche был взломан, что привело к выводу около $64 тыс. (~7 000 WAVAX) из кредитной делегации Aave V3 пользователя. Публичная функция выполняла произвольный target.call(data), сохраняя при этом делегацию пользователя, что позволило злоумышленнику вызвать borrow() в Aave с параметром onBehalfOf, установленным на жертву. Whitehat-бот обнаружил попытку взлома и вернул средства до того, как они были выведены.
Предыстория
Контракт ребалансировки (0x7a7b...a8c9) предоставляет функцию b2a13230(), предназначенную для ребалансировки позиции пользователя с плечом на Aave. Функция работает от имени пользователя через кредитную делегацию Aave V3: пользователь дает разрешение на заимствование, а ребалансер комбинирует эти кредиты с собственными средствами пользователя для корректировки позиции.
Анализ уязвимости
Первопричина заключается в том, что b2a13230() включает шаг target.call(data), а цель (target) и данные вызова (calldata) контролируются вызывающим лицом. Этот вызов выполняется, пока контракт всё еще действует в рамках кредитной делегации пользователя Aave V3. Таким образом, любая логика, вызванная на этом этапе, наследует право пользователя на заимствование. Нет белого списка разрешенных целей и нет ограничений на структуру данных вызова, поэтому вызов может обратиться к любому методу контракта, включая borrow() у Aave с onBehalfOf, установленным на пользователя.

Анализ атаки
Анализ основан на транзакции: 0xaaa1b2...35001b.
-
Шаг 1: Злоумышленник взял флэш-заем в
sAVAXиUSDC. Затем внес заемныйUSDCв Aave V3 через контракт ребалансера, чтобы обеспечить достаточное обеспечение для заимствования. Тем временем заемныйsAVAXбыл переведен непосредственно на контракт ребалансера для подготовки к последующему шагу пополнения после заимствования. -
Шаг 2: Злоумышленник снова вызвал функцию
b2a13230(). Сначала функция выполнила обычную операцию заимствования, а затем дошла до секции произвольного вызова. На этом этапе злоумышленник сформировал вызов для прямого обращения кborrow()в Aave V3 с параметромonBehalfOf, установленным на адрес жертвы. Поскольку жертва предоставила кредитную делегацию контракту ребалансировки, заимствование было успешно произведено. ЗаемныйWAVAXбыл переведен на контракт ребалансировки.

- Шаг 3: Злоумышленник еще раз вызвал
b2a13230(), на этот раз используя ребалансер для заимствованияWAVAXот своего собственного имени. Затем контракт использовал ранее заимствованныйWAVAX(полученный из позиции жертвы) для пополнения позиции злоумышленника и погашения кредита, что позволило ему извлечь прибыль.
Заключение
Дефект заключается в сочетании произвольного внешнего вызова внутри привилегированного контекста, обладающего делегированным кредитом. Каждый слой по отдельности был бы безопасен: ограниченный внешний вызов не мог бы злоупотребить делегацией, а произвольный вызов без делегации не смог бы переместить средства пользователя. Контракты, обладающие кредитной делегацией, никогда не должны предоставлять возможность произвольного внешнего вызова. Если такой вызов необходим, цели должны быть ограничены белым списком, а структура каллдаты — жестко проверена.
REVLoans (Juicebox)
20 апреля 2026 года REVLoans, расширение для заимствований в Juicebox, подверглось атаке в сети Ethereum на сумму около $50,7 тыс. Функция borrowFrom() принимала предоставленный вызывающим источником источник учета без проверки его регистрации в протоколе; поддельный контекст с 36 знаками после запятой запустил «короткий путь» той же валюты, который ошибочно пересчитал балансы в 10^18 раз. Две транзакции — одна для посева инфлированной учетной записи и вторая для заимствования у легитимного пула по завышенной цене акций — позволили вывести 21,77 ETH.
Предыстория
Juicebox — это гибридный протокол сбора средств и кредитования в Ethereum. Каждый проект имеет собственный ERC20 токен доли (здесь именуемый REV) и казначейство, разделенное между одним или несколькими терминалами. Терминал — это контракт, который физически хранит часть активов проекта и выступает точкой входа/выхода. У одного проекта может быть несколько терминалов, зарегистрированных в JBDirectory, и каждый тройной набор (terminal, project, token) имеет JBAccountingContext, определяющий (десятичные знаки, валюта), используемые для учета этого токена внутри терминала. Таким образом, REV — это требование на объединение излишков всех терминалов проекта, а не на конкретный терминал.
Пользователь может внести актив в терминал в обмен на свежеотчеканенный REV, либо обменять REV в терминале на пропорциональную долю излишка (за вычетом настраиваемого налога, оставляющего часть средств для оставшихся держателей). REVLoans (0x2db6...1846), отдельный контракт поверх системы, добавляет возможность заимствования. Пользователь сжигает REV в качестве обеспечения и берет кредит у одного из терминалов проекта, который позже можно погасить в обмен на повторный минтинг обеспечения. Сумма кредита оценивается по той же математике, что и погашение, поэтому заимствование экономически эквивалентно выводу средств под то же обеспечение.
Цена акций REV рассчитывается как (totalSurplus + totalBorrowed) / (REV.totalSupply + totalCollateral). Включение totalBorrowed в числитель делает цену нейтральной при заимствовании/погашении; также это означает, что завышенный показатель totalBorrowed напрямую повышает цену акции и позволяет вывести непропорционально большую сумму под небольшое обеспечение.
Анализ уязвимости
Первопричина — непроверенный ввод параметра source. borrowFrom() принимает предоставленный пользователем REVLoanSource source (структура с полями .terminal и .token) без проверки того, зарегистрирована ли эта пара для данного revnetId. Оба поля напрямую поступают в формулы расчета, поэтому контекст учета, возвращаемый source.terminal, полностью контролируется злоумышленником. Когда поле currency в этом контексте совпадает с полем терминала назначения, протокол выбирает «короткий путь» той же валюты, пропускает оракул цен и принимает предоставленные десятичные знаки и значения баланса как авторитарные.

Непроверенный source затем записывается в _loanSourcesOf[revnetId] и totalBorrowedFrom[revnetId][source.terminal][source.token] с помощью _addTo(), который также не проводит проверку регистрации.

Как только пара (source, revnetId) добавляется в учет, функция _borrowableAmountFrom() преобразует запрос на кредит в сумму к выплате. Она строит surplus = totalSurplus + totalBorrowed из _totalBorrowedFrom(), а затем передает этот излишек в JBCashOuts.cashOutFrom() вместе с количеством обеспечения вызывающего лица и предложением акций.

Ошибка с десятичными знаками живет на уровень глубже, в _totalBorrowedFrom(). Она проходит через _loanSourcesOf и суммирует каждую запись через mulDiv(tokensLoaned, 10**decimals, pricePerUnit). На пути «той же валюты» pricePerUnit = 10**decimals (точность 18 знаков цели), поэтому формула сокращается до tokensLoaned без изменений. Баланс, сохраненный в 36-значном учете, попадает в 18-значную сумму ETH завышенным в 10^18 раз.

Усиление эффекта происходит в cashOutFrom(). base = mulDiv(surplus, cashOutCount, totalSupply): так как в surplus доминирует раздутый totalBorrowed, даже крошечное cashOutCount (обеспечение) приводит к непропорционально огромной выплате.

Анализ атаки
Атака состояла из двух транзакций. Первая «загрязняет» учет REVLoans: 0xc46cb7...dead1f. Вторая выводит средства из пула против легитимного терминала: 0x9adbd6...a8f938.
- Шаг 1: Злоумышленник вызвал
borrowFrom()сterminalиtokenв источнике кредита, указывающими на фейковый контракт, внеся небольшое количествоREVв качестве обеспечения. REVLoans не проверял, зарегистрирован ли терминал для данного revnet, и распознается ли токен.

- Шаг 2: REVLoans запросил у фейкового терминала контекст учета, который вернул поддельный
(decimals=36, currency=ETH-code(61166)). Поскольку исходная и целевая валюты совпали, REVLoans применил «короткий путь», пропустил оракул и провел математику вывода над реальными излишкамиETHлегитимных терминалов, пересчитанными в 36-значную единицу злоумышленника, завысив фигуру в 10^18 раз.

- Шаг 3: REVLoans зарегистрировал
(fake terminal, fake token)в_loanSourcesOfи записал раздутое число вtotalBorrowedFrom. Фейковый терминал «выплатил» средства, просто подтвердив получение их на хранение; реальныеETHне перемещались. Транзакция завершилась с манипулированным в сторону увеличенияtotalBorrowedи сожженным маленьким обеспечениемREV.

- Шаг 4: Злоумышленник снова вызвал
borrowFrom(), на этот раз передав легитимный терминалETHв качестве источника и крошечное обеспечение вREV. Математика вывода сработала уже в реальных 18-значных единицахETH.

- Шаг 5: При расчете
totalBorrowedREVLoans прошел по_loanSourcesOfи встретил запись с шага 3. Поскольку валюта этой записи всё еще совпадала сETH, снова сработал «короткий путь», и 36-значный сохраненный баланс был добавлен в 18-значную суммуETHзавышенным в 10^18 раз.totalBorrowedтеперь доминировал фейковым долгом, а числитель цены акции был колоссально раздут.

- Шаг 6: Математика вывода вернула сумму кредита, соразмерную раздутому числителю, который злоумышленник заранее настроил так, чтобы он был чуть меньше реального излишка легитимного терминала. Легитимный терминал выплатил эту сумму, практически осушив весь пул в пользу атакующего.

Заключение
Первопричина — два накладывающихся друг на друга пробела: пары (terminal, token) принимаются без проверки регистрации revnet, а «короткий путь» суммирует балансы источников в целевую сумму без нормализации различий в количестве десятичных знаков. Любой из этих факторов по отдельности был бы менее опасен; вместе они позволяют злоумышленнику внедрить произвольную запись totalBorrowedFrom и обналичить её по номинальной стоимости. Исправление: проверять (terminal, token) в соответствии с зарегистрированными терминалами revnet и нормализовать балансы по сохраненной шкале десятичных знаков источника перед их сложением.
Volo Vault
22 апреля 2026 года Volo, хранилище доходности в сети Sui, зарабатывающее за счет размещения пользовательских депозитов в протоколе кредитования Navi, потеряло около $3,5 млн после того, как был скомпрометирован приватный ключ оператора. В коде хранилища не было ошибок; злоумышленник просто выполнил легитимный операторский путь с украденными учетными данными и вывел депозиты Volo из Navi.
Предыстория
Volo — это хранилище (0xcd86...27fefa), Navi — подлежащий протокол кредитования. Хранилище владеет Navi AccountCap (capability-объект в Sui, разрешающий вывод средств с аккаунта Navi, принадлежащего Volo), и делегирует перемещения стратегии роли оператора. Чтобы внести или вывести средства в Navi, оператор вызывает start_op_with_bag_v2(), перенося AccountCap из хранилища во временный мешок (bag), а затем deposit_with_account_cap() / withdraw_with_account_cap_v2() использует этот Cap для перемещения средств.
Анализ уязвимости
Первопричина — операционная ошибка (утечка ключа), а не уязвимость уровня контракта. Путь стратегии Volo делегирует право на вывод средств любому, кто обладает приватным ключом оператора: функция start_op_with_bag_v2() выполняет всего две проверки (assert_operator_not_freezed и assert_single_vault_operator_paired), обе из которых лишь подтверждают, что предоставленная возможность принадлежит зарегистрированному оператору. После этого withdraw_with_account_cap_v2() принимает любого вызывающего, способного предъявить извлеченный AccountCap. Любой, владеющий приватным ключом оператора, может выполнить тот же путь, что и легитимные операции.

Анализ атаки
Анализ основан на транзакции AQw9wM...3RUS.
- Шаг 1: Злоумышленник вызвал
start_op_with_bag_v2в@volosui/volo-vault::operationс украденным ключом оператора, поместив NaviAccountCapво временный мешок.

-
Шаг 2: Злоумышленник использовал
bag::remove, чтобы извлечьAccountCapиз мешка. -
Шаг 3: Злоумышленник вызвал
withdraw_with_account_cap_v2в@navi-protocol/lending::incentive_v3с извлеченнымAccountCap, выведя депозиты Volo из Navi.

- Шаг 4: Злоумышленник использовал
bag::add, вернувAccountCapна место, закрыл операцию и вывел средства.
Заключение
Дефект является структурным: один ключ оператора, полная власть на вывод, полное отсутствие контроля. Три изменения уменьшают ущерб от компрометации ключа: разделение роли оператора через мультиподпись или пороговую схему, добавление тайм-лока на исходящие выводы (это дает возможность оспорить необычный запрос до исполнения), и ограничение прав оператора (только депозит и ребалансировка, в то время как пользовательские выводы идут через отдельный механизм).
Kipseli Router
22 апреля 2026 года роутер Kipseli в сети Base был взломан на сумму около $72,35 тыс. Роутер использует котировку, возвращаемую внешним инструментом (USDC-only), как сумму трансфера выходного токена, не проверяя, что выходной токен равен токену котировки. Злоумышленник обменял 0,04 WETH на cbBTC по пути, который котировщик на самом деле не поддерживает, получив возвращаемое значение в шкале USDC (92 610 395) как необработанные единицы cbBTC (≈0,926 cbBTC).
Предыстория
Kipseli Router (0x579f...9a07) — это контракт исполнения обмена, поддерживаемый внешней системой котирования. Контракт не является открытым; анализ основан на декомпилированном байт-коде. Вместо прямого расчета цен обмена из AMM-пулов в сети, он запрашивает у котировщика сумму вывода (amountOut) и выполняет трансфер на основе этого значения. В нормальном режиме пользователь отправляет tokenIn в кошелек протокола, а роутер вытягивает tokenOut из того же кошелька и пересылает получателю. Протокол настроен на один QUOTE_TOKEN, и логика котирования деноминирована в USDC (6 знаков).
Анализ уязвимости
Дефект охватывает два слоя. На стороне роутера функция 0xcce096f3() получает котировку v0 через котировщик 0x592() и передает её без изменений в 0xd88() как tokenOut.transferFrom(_wallet, receiver, v0). Роутер никогда не проверяет, что tokenOut равен QUOTE_TOKEN, поэтому USDC-значение (6 знаков) переводится как cbBTC (8 знаков). На стороне котировщика AMM-система PropAMM разработана исключительно для пар токен-USDC, но принимает неподдерживаемые маршруты (WETH -> cbBTC) без возврата (revert), молча игнорируя tokenIn и возвращая значение в шкале USDC, как если бы обмен был валидным.

Анализ атаки
Анализ основан на транзакции 0x96edee...3db3bb.
- Шаг 1: Злоумышленник вызвал роутер с
tokenIn=WETHиtokenOut=cbBTC. АмМ не поддерживал этот путь, но не сделал откат, а котировщик0x592()вернул значение в шкалеUSDC— 92 610 395 (≈92,61USDC).

- Шаг 2: Роутер использовал это значение напрямую как сумму трансфера
cbBTC. 0,04WETH(≈$95) поступило в систему, а 92 610 395 единицcbBTC(≈0,926cbBTC, ≈$72,35 тыс.) ушло из кошелька протокола злоумышленнику.

Заключение
Эксплойт сработал, потому что ни одна из сторон не проверяла корректность входных данных. Исправления: на стороне роутера — подтверждать tokenOut == QUOTE_TOKEN или нормализовать котировку; на стороне котировщика — возвращать ошибку при неподдерживаемых путях, а не молча отдавать значение.
Purrlend
25 апреля 2026 года протокол кредитования Purrlend на HyperLiquid и MegaETH потерял حوالي $1,5 млн после компрометации приватного ключа. Злоумышленник захватил роль моста (bridge) и выпустил не обеспеченные pTokens (токены-квитанции Purrlend), после чего использовал их как обеспечение для вывода реальных активов из пула.
Предыстория
Purrlend (0x81d5...a702) — это протокол кредитования с моделью учета, аналогичной Aave. Когда пользователи вносят активы, они получают pTokens (аналог aTokens), представляющие их позицию и служащие обеспечением. В протоколе есть роли: администратор пула, администратор рисков и мост. Мост предназначен для кросс-чейн учета: он минтит pTokens для отражения депозитов в другой сети.
Анализ уязвимости
Триггером стала компрометация ключей администраторов и роли моста. Ошибка дизайна заключалась в отсутствии привязки минтинга pToken к каким-либо доказательствам кросс-чейн эскроу. Функция минтинга позволяет выпускать токены на любой адрес без проверки того, был ли реальный депозит в другой сети. В других местах протокола pTokens считаются валидным обеспечением. Таким образом, несанкционированный выпуск переводится напрямую в возможность вывода активов.
Анализ атаки
Анализ основан на транзакции 0xb96cff...dbbf24 в MegaETH.
- Шаг 1: Злоумышленник через
MultiSendCallOnlyназначил себя администратором пула, рисков и моста, включивWETHкак заемный актив.

-
Шаг 2: Выступая как мост, злоумышленник выпустил огромное количество
pTokensна свой адрес без реального обеспечения. -
Шаг 3: Злоумышленник использовал фейковые
pTokensкак обеспечение и вывелWETHиз пула.
Заключение
Необходимо внедрить пороговые схемы управления (мультисиг) для чувствительных ролей и требовать Verifiable Proof of Escrow для минтинга через мост. Проверка доказательства при выпуске — это единственный надежный способ исключить риск компрометации одного ключа.
SingularityFinance
26 апреля 2026 года хранилище dynBaseUSDCv3 в сети Base потеряло ~$413 тыс. Из-за неверной настройки типа комиссии Uniswap V3 (42, которой не существует) оракул цен Resolve не существовал, и функция возвращала 0 вместо возврата ошибки (revert). Хранилище оценило резервы в 0, что позволило злоумышленнику выпустить почти все токены долей через крошечный депозит USDC и обналичить резервы.
Предыстория
Хранилище (0x67b9...4dcd) агрегирует доходные токены. Цена рассчитывается как (base, quote, fee) через TWAP из Uniswap V3.
Анализ уязвимости
При вызове IUniswapV3Factory.getPool с некорректным fee возвращается address(0). В коде реализован ошибочный возврат нуля вместо отката транзакции. В итоге totalAssets() учитывал только USDC, занижая общую стоимость активов.

Анализ атаки
Анализ на основе транзакции 0x00b949...8d3732.
- Шаг 1: Флэш-заем на 100K
USDC. - Шаг 2: Депозит. Из-за того, что остальные токены оценивались в 0, злоумышленник получил огромную долю акций.
- Шаг 3: Погашение долей ( redemption) с получением всех имеющихся в хранилище активов.
Заключение
Необходимо проверять параметры оракула при деплое и валидировать результат getPool.
Scallop
26 апреля 2026 года Scallop на Sui потерял ~$142,7 тыс. Функция обновления наград не проверяла соответствие объекта отслеживания наград кошельку пользователя, что позволяло вытягивать фиктивный баланс из заброшенных объектов вознаграждения.
Предыстория
Scallop использует модель spool: пользователи вносят активы, получают MarketCoin, стейкают их и зарабатывают points, которые меняют на RewardsPool.
Анализ уязвимости
Дефект в spool::user::update_points кроется в отсутствии проверки account.spool_id == object::id(spool). Злоумышленник мог подставить старый, «заброшенный» объект Spool с накопленным огромным index, что позволяло мгновенно начислить себе огромное количество очков.

Анализ атаки
Анализ на основе транзакции 6WNDjC...NfVL.
- Шаг 1: Создание аккаунта в целевом пуле.
- Шаг 2: Вызов
update_pointsс использованием заброшенногоdonor_spoolс высоким коэффициентомindex. - Шаг 3: Обмен начисленных (фейковых) очков на реальные токены в
RewardsPool.
Заключение
Необходимо добавить проверку привязки spool в функции update_points и ограничить размер начисления очков за один вызов.
О компании BlockSec
BlockSec — поставщик комплексных услуг в сфере безопасности блокчейн-проектов и крипто-комплаенса. Мы создаем продукты для проведения аудита кода, обнаружения атак в реальном времени, анализа инцидентов и AML/CFT-соответствия.
BlockSec опубликовала множество работ по безопасности на престижных конференциях, сообщала о ряде 0-day уязвимостей в DeFi, заблокировала многочисленные хакерские атаки, сохранив более 20 миллионов долларов, и обеспечила безопасность активов на миллиарды долларов.
- Официальный сайт: https://blocksec.com/
- Twitter: https://twitter.com/BlockSecTeam
- 🔗 Аудиторский сервис BlockSec : Отправить запрос
- 🔗 Phalcon Security APP: Заказать демо
- 🔗 Phalcon Compliance



