Автор: 九九
Редакция: 77
Предыстория
19 августа 2026 года известный проект межсетевого моста Allbridge подвергся атаке, ущерб составил около 190 000 долларов. Однако на этот раз атака растянулась почти на месяц. Ниже приведен подробный анализ этого инцидента от команды по безопасности SlowMist:
Предварительные знания
Чтобы понять эту атаку, нам сначала нужно разобраться в протоколе Circle CCTP и его системе межсетевой передачи сообщений.
CCTP — это межсетевой протокол переводов Circle. Его базовый принцип заключается в том, что на исходной цепочке уничтожается USDC, а на целевой цепочке заново чеканится эквивалентное количество USDC. Таким образом можно избежать того, чтобы мостовой контракт произвольно увеличивал баланс.
Обычно передача по CCTP выполняется по следующей схеме:
TokenMessenger на исходной сети уничтожает USDC
-> Circle MessageTransmitter аутентифицирует и пересылает сообщение
-> TokenMessenger на целевой сети Circle принимает сообщение
-> После валидации TokenMessenger выпускает USDC
-> И только после того, как Router увидит реальное поступление, он переводит USDC пользователю
Circle MessageTransmitterV2 — это контракт, отвечающий за передачу сообщений. Он формирует attestation, то есть подпись-протверждение Circle для указанного кроссчейн-сообщения. Однако это доказательство лишь подтверждает, что содержимое сообщения было заверено Circle, и не позволяет отдельно доказать, что сумма, указанная в сообщении, реально произошла как перевод.
Circle TokenMessengerV2 на целевой сети отвечает за чеканку. После получения сообщения MessageTransmitterV2 находит контракт обратного вызова по параметру recipient в заголовке сообщения. Нормальное CCTP-сообщение задает этот адрес как TokenMessengerV2 целевой сети. Затем он проверяет исходный TokenMessenger, токен, сумму и адрес получателя; после прохождения проверок происходит чеканка USDC.
Модуль CCTP от Allbridge находится после этой стадии процесса. Он должен привести уже завершенные входящие операции в формат записей, которые понимает Router, после чего Router переводит токены пользователю. На этом этапе есть важный момент: валидность attestation не означает, что на исходной сети действительно произошло сжигание токенов; она не означает, что на целевой сети уже выполнена операция чеканки токенов; и она не означает, что Router реально получил соответствующие USDC. До этого момента мы можем понимать, что sendMessage от Circle — универсальный интерфейс: любой может вызвать его, передав некоторый содержательный блок кроссчейн-сообщения, и Circle заверит эту часть данных. Сам по себе вызов этого интерфейса не уничтожает USDC и не чеканит USDC автоматически. Для нормального CCTP-перевода в исходной сети также требуется участие TokenMessenger. Он сначала сжигает USDC, а затем создает сообщение, содержащее информацию о сжиганных токенах. В рамках этой атаки атакующий просто сконструировал кроссчейн-сообщение, обойдя шаг сжигания USDC.
Первопричина
在 Allbridge 的 CCTPTokenMessenger 合约中,接收跨链消息的 receiveCctpMessage 函数缺少对 CCTP 消息头中 sender 字段是否与远端 TokenMessenger 相等的检查,recipient 字段也没有检查是否等于 Circle 的 TokenMessengerV2 合约,导致 MessageTransmitterV2.receiveMessage 会把转发的跨链消息交给攻击合约来判断代币是否铸造成功,由于在本合约中没有再检查 Router 的 USDC 余额在记账前是否是真实增加的,合约直接信任了攻击者构造的消息中的金额,最终将其记账成可付款余额(跨链消息的 hookData 中 messageHash 对应的 receivedTokenAmount 数值)。
此次在 hookData 中也没有提供任何检查保护。Router 在执行付款时会根据调用参数重新计算 messageHash,然后再查询这个 hash 先前所记录的内部入金余额。而攻击者可以在 Polygon 发消息之前,离线算好同一组参数对应的 hash,再把 messageHash 放进直接放入跨链消息的 hookData 中。这样一来,匹配的是攻击者自己创建好的内部记录,和真实资产结算无关。
因此攻击者可以在 Polygon 上直接调用MessageTransmitterV2.sendMessage 构造任意跨链消息,并等 Circle 对其签名后,使得 Base 链的 attestation 验证成功,该伪造消息被当作真实跨链收款,最终触发 Router 转出代币。
Анализ шагов атаки
1. 26 июля 2026 года в 0:00 атакующий заранее напрямую вызвал функцию sendMessage контракта Circle MessageTransmitterV2 в Polygon. Это была операция по отправке универсального кроссчейн-сообщения; транзакция сгенерировала событие MessageSent, но фактического уничтожения USDC не произошло. Затем Circle подпишет полное сообщение, чтобы выдать attestation — это действие выполняется нормально в соответствии с ожиданиями протокола.

消息被填成了 CCTP 风格的数据。源域是 Polygon,目标域是 Base,声明金额为 1,000,000 USDC,feeExecuted 为零,destinationCaller 指向 Allbridge 的 CCTPTokenMessenger 合约。攻击者把消息头 recipient 设置为自己的合约,把消息正文中的 sourceSender 设置成配置里的远程 Messenger 地址,还把提前算好的 Router messageHash 放进 hookData,方便后续验证使用。
2. После создания этого вредоносного кроссчейн-сообщения атакующий ждал около 24 дней. Поскольку Base Router — это маршрутизатор-посредник, обычно у него нет длительного хранения крупных объемов ликвидности. Лишь 19 августа 2026 года, когда Allbridge relayer только что отчеканил USDC в Router по CCTP-внесению от другого пользователя (сумма примерно 191,112 USDC), баланс Router достиг примерно 191,156 USDC.
Этот баланс относится к кроссчейн-фондам, ожидающим перевода реальным пользователям; атакующий дождался крайне короткого окна ожидания — через шесть секунд после реального входящего поступления — и начал выполнение основной транзакции атаки.

3. Контракт атакующего сначала вызывает функцию receiveCctpMessage контракта CCTPTokenMessenger, передавая сообщение и данные подписи attestation, полученные в Polygon-транзакции; при этом проверки destinationCaller и sourceSender проходят успешно (обе — сконструированы и контролируются атакующим). Затем атакующий вызывает функцию receiveMessage контракта Circle MessageTransmitterV2, где в соответствии с recipient в заголовке сообщения выполняется обратный вызов контракту атакующего. Контракт атакующего напрямую возвращает успех и не выполняет ожидаемую операцию чеканки токенов контрактом Circle TokenMessenger. При этом и Allbridge не подтверждает повторно баланс Router, и не проверяет, что целевой контракт, которому выполняется обратный вызов, равен Circle TokenMessengerV2: сразу записывается amount - feeExecuted в receivedMessages[messageHash], создавая внутренний credit на 1,000,000 USDC.


4. Поскольку целевая сумма, сконструированная в кроссчейн-сообщении, созданном ранее атакующим, составляла 1,000,000 USDC, а у Router на тот момент было примерно 191,156 USDC, атакующий сначала предоставил Router 808,844 USDC через Aave flash loan, чтобы временно довести баланс до суммы, указанной им в фальшивом сообщении, тем самым обеспечив возможность выполнения последующего вывода токенов.

5. Далее атакующий вызывает функцию Router receiveToken для обработки расчетов по получению. Router сначала еще раз пересчитывает hash на основе параметров вызова; полученное значение совпадает с messageHash, который ранее атакующий сам уже посчитал и сформировал в hookData. Затем он проверяет только, что запись receivedTokenAmount, соответствующая messageHash в контракте CCTPTokenMessenger, больше нуля — и это трактуется как полученные реальные токены депозита. Поскольку Router взимает комиссию 0,1%, после вычета комиссии оставшиеся 999,000 USDC напрямую переводятся на контракт атакующего.
В ходе всего процесса Router проверяет лишь, что credit существует в контракте CCTPTokenMessenger, и при этом не подтверждает повторно, что этот credit соответствует фактическому поступлению в блокчейне активов сопоставимого масштаба.


6. После того как атакующему удается похитить 999,000 USDC, он возвращает Aave основную сумму 808,844 USDC и оплачивает комиссию по flash loan около 404.422012 USDC. В итоге у него остается примерно 189,751.554381 USDC — прибыль от атаки. Эта транзакция практически полностью опустошила 191,156 USDC Router. Основная часть потерь связана с реально пришедшими, но еще не переведенными пользователям кроссчейн-входящими средствами.
Интересно, что комиссия Router в размере 1,000 USDC, взятая в ходе описанного выше, позже была похищена другим атакующим, который использовал ту же методику повторной атаки.
Итоги
Ключевая проблема этого инцидента связана с тем, что в Allbridge отсутствует проверка обоснованности кроссчейн-сообщений. Attestation от Circle может лишь подтвердить, что содержимое сообщения не было изменено, но не доказывает, что кроссчейн-сообщение действительно инициировало операцию сжигания или чеканки токенов. Allbridge напрямую доверяет сумме, адресу источника средств и messageHash, которые атакующий сам сконструировал в сообщении CCTPTokenMessenger, и записывает это как выплачиваемый баланс, воспринимая это как реальное количество входящих средств.
Команда по безопасности SlowMist рекомендует при исправлении проекта одновременно соблюдать три границы:
1. Параметр sender в заголовке сообщения должен соответствовать контракту компонента исходного доверенного уровня;
2. Параметр recipient в заголовке сообщения должен быть ограничен контрактом Circle TokenMessengerV2 целевой сети;
3. Запись о выплачиваемом депозите может быть создана только после того, как баланс USDC Router действительно увеличится за счет чеканки.
Для систем кроссчейн-мостов наиболее важным условием является то, чтобы сообщение, прошедшее разумную валидацию и проверки, было необходимым условием для кроссчейн-расчетов; именно реальное поступление активов является основанием для финальной выплаты Router.

