背景
2026年6月14日、廃止されたAztec Connect RollupProcessorコントラクト(0xff1f2b4adb9df6fc8eafecdcbf96a2b351680455)が悪用された。攻撃者は、numRealTxsとdecoded_slotsの間の境界ギャップを悪用し、単一の原子的トランザクションを通じてL1プールから約219万ドル相当の資産を引き出した。Aztec Connectは2024年3月に廃止されたが、この不変コントラクトは未使用のユーザー資産を保有し続けていたため、リスクが継続的に存在していた。本記事では、コントラクトのソースコードとチェーン上のcalldataの両面から、今回の攻撃の完全な技術的詳細を再構成する。
攻撃の概要

脆弱性の根本原因
RollupProcessorV3 は rollup の決済を処理する際、L1 決済ループの走査範囲と ZK 公開入力ハッシュのコミット範囲の間に構造的なギャップが存在します。攻撃者はこのギャップを悪用し、31/32 の公開入力スロットの内容を ZK 証明で L2 ステートルートにコミットしつつ、L1 コントラクト層でのいかなる決済検証も経由しません。
Decoder.sol:numRealTxsは攻撃者によって完全に制御される
numRealTxs は calldata のオフセット 4516 から読み取られ、オンチェーンの制約は一切ありません:

decoded_slots を numTxsPerRollup の倍数に切り上げるのは、SHA256プリコンパイルのデータレイアウト要件である。しかし、この切り上げ操作は、numRealTxs と decoded_slots の間に攻撃者が自由に埋められるギャップ領域を生み出す。
RollupProcessorV3.sol:決済ループはnumRealTxs個のスロットのみをカバーします
安全仮定の破綻
正常なプロセスにおけるセキュリティの前提は、すべての公開入力スロットが、L1コントラクト層で検証される(デポジット時にpendingDepositBalanceを減算)か、ZK回路によってpublicValue == 0と制約されることである。しかし、本脆弱性のシナリオでは:
- SHA256のプリコンパイルは、すべての32個のスロットをカバーします(実際の入力は8192バイト=32×256バイト)。gapスロットの内容はZK証明によってコミットされています。
- L1決算ループは最初の1つのスロットのみを巡回し、gapスロット[2..32]はL1レベルでの検証を受けません。
- ZK回路によるgapスロットのpublicValueへの制約(0であるべき)が攻撃者によって回避されたり、適用されなかったりしました。
三つの防衛ラインは互いに依存していますが、いずれもgapスロットのセキュリティを単独で保証することはできません——ZK回路の制約が欠如した場合、L1契約層も同様にそれを検出できません。
二重経路分岐モデル
同じcalldataが、2つのパスで異なる上限で消費されています:

「どのスロットが有効か」に対する認識の不一致(ZKは32個と認めるが、L1は1個しか認めない)が、無から通貨を生成する根本原因である。
攻撃フロー
攻撃取引 0x074ec931…aee1 には、14 回の processRollup() 呼び出しが含まれ、前半7回が新規発行、後半7回が引き出しという2段構造となっており、すべて単一の原子的取引内で完了しています。
第1段階:鋳造 — L2上で資産を空から取得(Rollup #13277–13283、7回)
1. 攻撃者EOA 0x0f18d8b44a740272f0be4d08338d2b165b7edd17が、総括エントリーコントラクト0x06f585f74e0da633ae813a0f23fb9900b61d0fcdを呼び出し、セレクタ0x6f3ce701をトリガーしました。
2. 総合コントラクトが3つのリレー・コントラクトを順次呼び出し、各リレー・コントラクトには複数の悪意あるrollup calldataがハードコードされています。各calldataの重要なパラメータ:
- numRealTxs = 1、rollupSize = 1024、numInnerRollups = 32
- 最初のスロット(L1表示):proofId = 0(noop)、publicValue = 0
- 2〜32番目のスロット(31個のgapスロット、L1は非表示):proofId = 1(デポジット)、publicValue = N、publicOwner = 攻撃者のL2アドレス
- ZK証明を付属(回路の制約されていないギャップスロットのpublicValueを0に設定)
3. リレイコントラクトAは、RollupProcessor.processRollup()を順次呼び出します(Rollup #13277–13281、5回):
- Verifier が ZK 証明の検証に成功 — SHA256 コミットメントがすべての 32 セルをカバー
- L1決算サイクル end = 1 × TX_PUBLIC_INPUT_LENGTH = 1 スロット、noopのみ処理
- gap スロット [2..32] の偽造預金が ZK 認証により新しい Merkle ルートに組み込まれる → 攻撃者の L2 残高が 5 × 31N 増加
4. リレイコントラクトBは、Rollup #13282–13283を同様の方法で2回処理し、攻撃者のL2残高にさらに2×31Nが追加される。これにより、攻撃者のL2アカウントは合計7×31Nの裏付けのないチャージを獲得したが、L1の資金プールは1ペニーも減少していない。
第二段階:出金 — L2の虚偽残高をL1資産に換金(Rollup #13284–13290、7回)
攻撃者は、7回の引き出しロールアップを用いて、铸造段階で得たすべてのL2残高をL1資産に交換しました:
- Rollup #13284(DAI):withdraw() → RollupProcessor に直接 270,513.054 DAI を振替 → 0x0f18…edd17
- Rollup #13285(wstETH):振替 167.890 wstETH → 攻撃者
- Rollup #13286(yvDAI):振替 4,873.857 yvDAI → 攻撃者
- Rollup #13287(yvWETH、中継契約Cが引き継ぎ):16.570 yvWETHを振替 → 攻撃者
- Rollup #13288(LUSD):振替 9,273.734 LUSD → 攻撃者
- Rollup #13289(yvLUSD):振替 359.047 yvLUSD → 攻撃者
- Rollup #13290(ETH、最終取引):RollupProcessor が内部 CALL を通じて 908.987 ETH を攻撃者に転送。
単一原子的トランザクションが成功(gasUsed = 4,513,539)し、契約レベルでは部分的なロールバックは不可能です。攻撃者は、RollupProcessorの正当なユーザー資産プールから約219万ドルを不正に取得しました。
資金追跡
チェーン上での証拠追跡に基づく(2026-06-15時点、事件発生から約1日後)、盗難された資金の状況は以下の通りです:
すべての資産が、単一のトランザクション内でRollupProcessorから中間攻撃契約0x06f585…d0fcDを経由して、攻撃者のEOA 0x0F18D8b44a740272f0be4d08338d2b165b7EdD17に直接転送されました。中間契約には残高は残っていません。
現在、盗まれた資金は100%、攻撃者のEOAにそのまま残っており、マネーロンダリングは開始されていません。


要約
今回の攻撃の核心的な教訓は、ZK-Rollup コントラクトの決済ループの上限が、ZK公開入力ハッシュのコミットメント範囲と厳密に一致している必要があるということである。L1コントラクト層のループ境界numRealTxsとSHA256コミットメントのdecoded_slotsの間にギャップが存在する場合、ZK回路がギャップスロットに制約を課すという安全仮定は攻撃者によって回避される可能性がある——L1は、ZK証明によってコミットされたすべての公開入力スロットを独立して検証しなければならず、検証責任を回路層に委ねてはならない。
慢霧セキュリティチームは、Rollupシステムのデプロイ前に、L1/L2ステータス境界におけるロジックの一貫性、calldataのデコードにおける信頼境界、およびZK公開入力のオンチェーン二次検証に重点を置いた完全な外部セキュリティ監査を実施することを推奨します。廃止されたがレガシー資産を保有する契約については、継続的なリスクを排除するために、秩序ある資産移行または破壊を実施することを推奨します。
本記事は、SlowMist脅威インテリジェンスチームがMistEye脅威インテリジェンスシステム、MistTrack追跡プラットフォーム、およびSlowMist Agent AIによる分析を組み合わせて作成しました。ご質問やフィードバックがございましたら、お気軽にお問い合わせください。

