先週(2026年5月27日〜2026年5月30日)、BlockSecは複数のブロックチェーンエコシステム全体で複数の攻撃インシデントを確認しました。以下の表は、推定総損失額約1,600万ドルにのぼる5つの注目すべきインシデントです。
| 日付 | インシデント | 種類 | 推定損失額 |
|---|---|---|---|
| 2026/05/27 | The SquidRouterModule Contract | 不適切な入力バリデーション | ~$3.2M |
| 2026/05/29 | Stake DAO | プライベートキーの侵害 | ~$91K* |
| 2026/05/29 | DxSale | 不適切なビジネスロジックとキーの侵害 | ~$7.3M |
| 2026/05/30 | Gravity Bridge | オフチェーン署名プロセスの脆弱性 | ~$5.4M |
| 2026/05/30 | Alephium | オフチェーン署名プロセスの脆弱性 | ~$300K* |
*補足事項:
- Stake DAOのインシデントでは、攻撃者がデプロイヤーのプライベートキーを侵害し、それを使用してArbitrum上の
vsdCRVコントラクトにあるLayerZero v2 OFTピアを再構成することで、5.4兆枚のvsdCRVを鋳造しました。DEXの流動性が限られていたため、プールが枯渇するまでに換金できたのは約9.1万ドルのみでした。 - Alephiumのインシデントでは、ブリッジの保管資産(Ethereum上の
USDT、USDC、WETH、WBTC、およびBNB Chain上のUSDT、WBNB)約30万ドルの流出に加え、攻撃者は裏付けのないwALPHをEthereum上で1,370万枚鋳造しました。ブリッジは閉鎖されたため、攻撃者はこれらのトークンをAlephiumブリッジ経由で償還したり、再ブリッジしたりすることはできません。
詳細な分析のために選ばれた2つのインシデントは以下の通りです。
- The SquidRouterModule Contract: CrossCurveFiの攻撃と同様、同じクラスの統合ミスを繰り返しており、深い理解と厳格なセキュリティレビューなしにクロスチェーンロジックをフォークすることが、いかに継承された複雑さを即座に継承されたリスクへと変えてしまうかを示しています。
- DxSale: 長期にわたるこの攻撃のタイムラインは、悪用されていないレガシー契約が決して安全ではないことを示しています。プロトコルは休眠状態のインフラを継続的に監査し、特権アクセスを最小限に抑え、長年の沈黙をセキュリティの証明と決して勘違いしてはなりません。
Web3のための最高のセキュリティ監査人
ローンチ前に設計、コード、ビジネスロジックを検証します
今週のハイライト: DxSale
このインシデントは、長年放置されていたパッチ未適用のロッカー契約と、侵害されたデプロイヤーキーの組み合わせが、繰り返されるパターンを示しているため、今週のハイライトとして選ばれました。デプロイ時のコードを永続的に安全であると見なし、継続的な監査や特権のローテーションを行わないプロトコルは、いつでも武器化される可能性のある潜在的なリスクを抱えています。
2026年5月29日、BNB Chain上のトークン販売・流動性ロックプラットフォームであるDxSaleが攻撃され [1]、約730万ドルの被害が発生しました。トークン引出し関数には3つの状態更新の欠落が含まれており、有効なロックポジションを持つユーザーであれば誰でも、所有者の権限を必要とせず、繰り返し引き出しを行って共有プール全体を枯渇させることができました。EIP-7702委任を通じたDxSaleデプロイヤーキーの別個の侵害は、この攻撃の前提条件ではありませんでしたが、手数料の操作や他のユーザーによる新規ロック作成のブロックを可能にし、攻撃者の効率性を高めました。
背景
DxSaleは、BNB Chain上のトークン販売および流動性ロックプラットフォームです。「DxLock」コンポーネントにより、プロジェクト開発者はLPトークンをタイムロックされた保管庫(Vault)にロックでき、投資家に対して流動性がラグプル(持ち逃げ)されないという保証を提供します。
中核となるロックメカニズムは以下の通りです。ユーザーがロッカーコントラクトにトークンを預けると、呼び出し元のアドレスとトークンIDの組み合わせによってインデックス化されたロック記録が作成されます。各記録には、ロックが存在するかどうか、現在トークンがロックされているかどうか、ロック額、アンロックのタイムスタンプ、およびトークンアドレスが保存されます。ロック期間が終了すると、ユーザーはunlockToken(tokenId)を呼び出してトークンを引き出します。
ロッカーは多くのユーザーのトークンを共有残高として同時に保持するため、個々の割り当ては個別のロック記録を通じて正確に追跡する必要があります。プール全体のセキュリティは、各引き出しが呼び出し元の自身の記録を正しく検証し、転送後にそれを更新することに依存しています。
脆弱性分析
バグのあるコントラクト (0xeb3a...e449) 内のunlockToken関数には、3つの複合的な欠陥があり、それぞれが状態の更新やチェックの欠落となっていました。
function unlockToken(uint256 tokenId) public nonPayable {
require(_increaseLockTime[msg.sender][tokenId].field0_0_0); // ロックが存在する
require(_increaseLockTime[msg.sender][tokenId].field0_1_1); // トークンがロックされている
require(_increaseLockTime[msg.sender][tokenId].field2); // 金額 > 0
if (block.timestamp > _increaseLockTime[msg.sender][tokenId].field3) {
_increaseLockTime[msg.sender][tokenId].field0_1_1 = 0;
}
v0, v1 = _increaseLockTime[msg.sender][tokenId].field5_0_19.balanceOf(this);
require(v1 >= _increaseLockTime[msg.sender][tokenId].field2);
v2, v3 = _increaseLockTime[msg.sender][tokenId].field5_0_19.transfer(
msg.sender, _increaseLockTime[msg.sender][tokenId].field2
);
}
-
ロック期間の強制なし。 ロック期間は
requireではなくif文によって保護されていました。アンロック時間を過ぎる前に呼び出された場合、関数は関数を終了させる(revert)のではなく、単にロックフラグを解除せずにスキップするだけでした。これは、ロック期間に関係なく、いつでもトークンを引き出せることを意味していました。 -
ロック金額がゼロにならない。 呼び出し元にトークンを転送した後、関数は
field2(ロック金額)をゼロにしませんでした。その後のすべての呼び出しは同じ元の値を読み込み、毎回同じ額を引き出すため、無限引き出しループが作成されました。 -
個別の割り当てではなく共有残高のチェック。
balanceOf(this)の呼び出しは、呼び出し元の個々の割り当てではなく、コントラクトの合計トークン残高を検証していました。ロックポジションを小さく持つ呼び出し元であっても、コントラクトに十分なトークンが残っている限り、共有プール全体を枯渇させることが可能でした。
これら3つの状態更新の欠落により、関数からすべての終了条件が取り除かれました。呼び出しが途中で失敗することはない上、引き出し額が減ることもなく、残高チェックもコントラクトが完全に空になるまでブロックされませんでした。このバグは、ロックポジションを作成したユーザーであれば誰でも悪用可能であり、完全な引き出しに所有者権限は不要でした。
攻撃分析
EIP-7702委任を通じて運用されていたDxSaleのデプロイヤーアカウント(0x47bacf93)は、2026年4月15日以降、大量の所有権転送、手数料変更、複数のDxSaleコントラクト間でのLPアンロック操作など、異常な活動を示していました。2026年5月26日、デプロイヤーは標的となったロッカー(0xeb3a...e449)の所有権を攻撃者のコントラクト(0xc457...fa69)に譲渡しました。その2日後、攻撃者は5段階の枯渇攻撃を実行しました。
以下の分析は、代表的なトランザクション 0x437b26...c1b303 に基づいています。
-
ステップ1: 攻撃者はPancakeSwapで
BNBをBNBCトークンと交換し、流動性を提供して新しいCake-LP (BNBC/WBNB)ペアを作成し、約0.323枚のLPトークンを受け取りました。 -
ステップ2: 前の所有権譲渡によって取得した所有者権限を使用して、攻撃者は
changeFees(1)を呼び出してロック作成手数料を1 weiに設定し、次にcreateLockerを呼び出して、約0.323枚のLPトークンを新しいロックポジション(tokenId=131)に預け入れました。直後、攻撃者はchangeFees(10^36)を呼び出し、手数料を天文学的な数値に引き上げることで、他のユーザーが新しいロックを作成するのを防ぎました。 -
ステップ3: 攻撃者はエクスプロイト関数(
0x11b432b4)を呼び出し、1回のトランザクションでunlockTokenの繰返し実行を調整しました。複数のトランザクションを通じて、攻撃者は計画的にロッカーを枯渇させました。0x437b26...c1b303 はtokenId=131を介して161.4 LPトークンを枯渇させました。0x82f541...a9fa73 および 0x5dd61f...4298aa は追加のロックポジションを枯渇させました。0xac8f5e...d36df9 は478回の呼び出しを通じてtokenId=319から260.3 LPトークンを枯渇させました。 -
ステップ4: 攻撃者はPancakeSwapで
removeLiquidityを呼び出し、枯渇させたLPトークンを基盤となるトークン(BNBCおよびWBNB)に戻しました。 -
ステップ5: 攻撃者はPancakeSwap経由で基盤トークンを
WBNBおよびBUSDにスワップし、収益を外部アドレスへ送金しました。BSCScanは、この攻撃者コントラクトについて4日間(2026年5月28日〜5月31日)で123,447件のトランザクションを記録しました。
結論
このインシデントの根本的な原因は、unlockTokenにおける3つの状態更新の欠落です。それぞれに直接的な修正策があります。つまり、ifではなくrequireを使用してロック期間を強制すること、各引き出しの後にロック金額をゼロにすること、そしてコントラクトの合計残高ではなく、呼び出し元の個々の割り当てをチェックすることです。これら単独の欠陥でも攻撃には十分であり、ロックポジションを作成したユーザーは誰でも、所有権限なしに繰り返し呼び出すことで共有プール全体を枯渇させることができました。
EIP-7702委任を通じたDxSaleデプロイヤーの事前の侵害は、攻撃の前提条件ではありませんでしたが、攻撃者の効率を高める要因となりました。所有権を移転し手数料を操作することで、攻撃者はコストをほぼゼロでロックポジションを作成し、正当なユーザーが競合するロックを作成するのを防ぎました。運用面において、プロトコルはレガシーコントラクト、特にユーザー資金を保有するものを継続的に監査し、管理機能の単一キー管理を避ける必要があります。長年のインシデントフリーな運用は、監査されていないコードのセキュリティを保証するものではありません。
参考文献
- [1] DxSale発表
今週のその他のインシデント
The SquidRouterModule Contract
2026年5月27日、Ethereum上でSquidRouterModuleという未知のコントラクトが不適切な入力バリデーションにより攻撃され [1]、約320万ドルの損失が発生しました。根本原因は、以前のCrossCurveFi攻撃パターン [2] に類似したAxelar Bridge統合の乱用でした。当該コントラクトはAxelarゲートウェイを介したクロスチェーンメッセージを適切に検証していなかったため、攻撃者は被害者のトークンを認可し、構築済みの悪意あるプールへとスワップさせる不正なペイロードを捏造できました。偽トークンをデプロイしプールに流動性を提供した別のアドレスが、後に流動性を引き出し、実際の資産を抽出しました。この攻撃は86個のSafeウォレットに影響を与えました。名称とは裏腹に、SquidRouterModuleはSquidプロトコルチームによって構築、デプロイ、または運用されたものではありません [3]。
背景
このコントラクトは、Axelarクロスチェーンプロトコル上で構築されたSafeウォレット向けのクロスチェーン交換サービスモジュールです。当該コントラクトはexpressExecuteWithToken関数を提供し、クロスチェーンメッセージの確認前にトランザクションを実行する早期実行をサポートしています。ユーザーは、このサービスを利用する前に、Safeウォレット上でコントラクトのAPPROVEおよびSWAP権限を事前承認しておく必要があります。expressExecuteWithTokenが呼び出されると、コントラクトはペイロード内の操作手順をデコードし、SafeウォレットのexecTransactionFromModuleを呼び出してトークンの認可および交換操作を実行します。
脆弱性分析
脆弱なコントラクト (0x1f1d...23ca) 内の_executeWithToken関数は、srcAddressが定数squidRouterと等しいかどうかを確認するだけでした。しかし、srcAddressは呼び出し手が提供するパラメータであり、squidRouterは誰もがコントラクトから読み取れる不変の文字列でした。これにより、攻撃者は容易にチェックをバイパスし、任意のペイロード内容で_processPayload関数を実行することができました。

これに対し、正規のSquid RouterのexecuteWithToken関数はgateway.validateContractCallAndMint()を呼び出し、Axelarバリデーターネットワークがトランザクションを確認していない場合はNotApprovedByGateway()で反転(revert)させます。

脆弱なコントラクトは、expressExecuteWithTokenのパスにおいて、このようなゲートウェイ認可を強制していませんでした。Safeウォレットユーザーがモジュールに対して事前承認していたAPPROVEおよびSWAP権限と組み合わさることで、捏造されたペイロードは被害者の資金を直接操作することが可能でした。
攻撃分析
以下の分析は、トランザクション 0xd29d1c...3bb854 に基づいています。
攻撃の前、別の攻撃者アドレスが偽トークン(
0xe6Ff...3512)をデプロイし、複数のUniswap V3プールを作成しました。各プールは、価値のあるトークン(USDC、ENA、USDTなど)と偽トークンをペアにし、流動性を提供していました。
-
ステップ1: 攻撃者は悪意のあるcalldataを捏造し、検証チェックをバイパスするために既知の
squidRouterアドレスをsourceAddressとして使用して、当該コントラクトのexpressExecuteWithToken関数を呼び出しました。被害者がモジュールに対して事前承認していたAPPROVEおよびSWAP権限を通じて、捏造されたペイロードは被害者のSafeウォレットからUniswapプールへのトークン承認を強制的に行いました。 -
ステップ2: これらの強制的な承認を使用して、ペイロードは対応する悪意のあるプールを通じて、被害者のトークンを価値のない偽トークンと交換しました。
攻撃者はこの手法を複数のトランザクションで繰り返し、脆弱なコントラクトを承認していた合計86個のSafeウォレットを標的にしました。偽トークンをデプロイしプールに流動性を提供した別のアドレスが、後に流動性を撤去して真の資産を引き出し、最終的に約320万ドルの利益を得ました。
結論
このインシデントは、クロスチェーンメッセージ処理経路における不適切な入力バリデーションによって引き起こされました。唯一のセキュリティチェックは、呼び出し元が制御可能なパラメータをパブリックに読み取り可能な定数と比較することに依存しており、実際の保護機能は提供されていませんでした。Safeウォレットユーザーからの事前承認済みのAPPROVE・SWAP権限と組み合わさることで、攻撃者はクロスチェーンメッセージを捏造し、ユーザーの資金を盗むことができました。
このインシデントはCrossCurveFiの悪用 [2] に類似しています。どちらもAxelar Bridgeの統合において、受信したクロスチェーンメッセージを適切に検証できなかったケースです。クロスチェーンメッセージングインフラを統合する場合、宛先コントラクトはブリッジの認可メカニズムを通じてメッセージの真正性を独自に検証する必要があります。この検証をスキップして攻撃者が制御可能な入力に依存することは、その統合をオープンな攻撃対象へと変化させてしまいます。
参考文献
- [1] Phalcon Alert: SquidRouterModule exploit
- [2] Phalcon Alert: CrossCurveFi attack pattern
- [3] Squid Router clarification
BlockSecについて
BlockSecは、フルスタックのブロックチェーンセキュリティおよび暗号資産コンプライアンスプロバイダーです。当社は、コード監査(スマートコントラクト、ブロックチェーン、ウォレットを含む)、リアルタイムでの攻撃阻止、インシデント分析、不正資金の追跡、AML/CFT義務への対応を行うツールやサービスを構築し、プロトコルとプラットフォームのライフサイクル全体を支援しています。
BlockSecは権威あるカンファレンスで複数のブロックチェーンセキュリティ論文を発表し、DeFiアプリケーションのゼロデイ脆弱性を複数報告し、複数のハッキングを阻止して2,000万ドル以上の資産を救出し、数十億ドル相当の暗号資産を保護してきました。
-
公式ウェブサイト: https://blocksec.com/
-
公式Twitter: https://twitter.com/BlockSecTeam



