過去1週間(2026年3月9日~2026年3月15日)、BlockSecは8件の攻撃インシデントを検知・分析し、総損失額は約166万ドルと推定されます。以下の表はこれらのインシデントの概要を示しており、各ケースの詳細な分析は、後続のセクションで提供されています。
| 日付 | インシデント | タイプ | 推定損失額 |
|---|---|---|---|
| 2026/03/09 | EtherFreakers インシデント | 不良なビジネスロジック | 約25Kドル |
| 2026/03/10 | Alkemi インシデント | 不良なビジネスロジック | 約89Kドル |
| 2026/03/10 | MT インシデント | 不良なビジネスロジック | 約242Kドル |
| 2026/03/11 | AAVE 担保清算インシデント | 設定ミス | 約1.01Mドル |
| 2026/03/11 | Planet Finance インシデント | 不良なビジネスロジック | 約10Kドル |
| 2026/03/12 | AM インシデント | 不良なビジネスロジック | 約131Kドル |
| 2026/03/12 | DBXen インシデント | 不良なビジネスロジック | 約149Kドル |
| 2026/03/15 | Goose Finance インシデント | 不良なビジネスロジック | 約8Kドル |
EtherFreakers インシデント
概要
2026年3月9日、Ethereum上のNFTゲームであるEtherFreakersが、二重計上の誤りにより悪用され、約25Kドルの損失が発生しました。ゲーム内の各NFTは引き出し可能な「エネルギー」と呼ばれるETH残高を保持しています。ゲームのメカニズムとして、プレイヤーはattack()を使用して、あるNFTが別のNFTを捕捉し、ターゲットのエネルギーを請求することができます。しかし、コントラクトはターゲットの残高を支払いますが、その会計処理を完了する前にNFTを移転します。その後、転送フックが古い、支払い前のデータを読み取り、その一部をグローバル配当プールにフィードバックし、新しいETHの裏付けなしにプールを膨張させます。攻撃者はこの捕捉メカニズムをループさせ、グローバルインデックスを操作してから、NFTのバッチから過大評価された残高を引き出しました。
背景
EtherFreakersは、各NFT(「Freaker」と呼ばれる)が「エネルギー」と呼ばれる引き出し可能なETH残高を保持する、オンチェーンNFTゲームです。システムは配当プールのように機能し、特定の操作が発生すると、ETHの一部がすべてのFreakerに比例して分配されます。各Freakerの請求可能なETHは、グローバルアキュムレータfreakerIndexとトークンごとのシェアウェイトfortuneの組み合わせで追跡されます。
具体的には、会計式は energyOf = basic + (freakerIndex - index) * fortune です。 freakerIndexは _dissipateEnergyIntoPool(amount) が実行されると増加し、amountの80%がすべてのFreakerに、20%がクリエイターに分配されます。 charge()による直接入金は、freakerIndexに影響を与えずにbasicのみを増加させます。したがって、freakerIndexの増加は、常に実際のEtherがシステムに入ることで裏付けられるべきです。freakerIndexが対応するEtherの流入なしに成長した場合、Freakerはコントラクトが実際に保持している以上のEtherを償還できます。
脆弱性分析
根本原因は、EtherFreakコントラクト(0x3A27...c0f33)における不正な実行順序です。捕捉が成功すると、attack()関数は以下の手順で実行されます。
- 237行目:
targetCharge(ターゲットNFTの全エネルギー)を防御者に直接ETH転送として支払います。エネルギーは消費されました。 - 240行目: NFTを移動するために
_transfer(defender, capturer, targetId)を呼び出します。内部で、_transfer()はERC-721フック_beforeTokenTransfer()を呼び出し、これはenergyOf(targetId)の0.1%で_dissipateEnergyIntoPool()を呼び出します。これは_dissipateEnergyIntoPool()への最初の呼び出しであり、ステップ5がまだ発生していないため、古い値が読み取られます。 - 241行目: 明示的に
_dissipateEnergyIntoPool(sourceSpent)を呼び出します。これは2回目の呼び出しであり、通常のゲームロジックの一部です。 - 244-251行目:
sourceIdとtargetIdの両方についてenergyBalancesを更新します。
バグはステップ2にあります。energyBalances[targetId]がまだ更新されていないため、フックは支払い前の残高を依然として認識し、すでに消費されたエネルギーの一部を配当プールにフィードバックします。ステップ1の直接ETH支払いとステップ2のプール入力は、両方とも同じエネルギーから引き出され、新しいEtherの裏付けなしにfreakerIndexを膨張させます。


_dissipateEnergyIntoPool()が呼び出されるたびにfreakerIndexが増加します。

攻撃分析
以下の分析は、トランザクション 0x89e24d...9abd2942 に基づいています。
-
ステップ1:1,700 WETH を借入。
-
ステップ2:攻撃者が制御するアドレスの下で、2つの新しいFreaker(トークン590、591)をミント。
-
ステップ3:ゲームの
attack(590, 591)関数を繰り返し呼び出し、捕捉成功のブランチを維持。 -
ステップ4:成功するたびに、同じペアを再利用できるように、トークン591をヘルパーに戻す。
-
ステップ5:成功するたびに、
freakerIndexがシステムによって実際に保持されているEtherを超えて膨張。 -
ステップ6:インデックスが十分に高くなった後、以前制御していたFreakerのバッチを解放。トークンID 496から520は、それぞれ0.278052246002402082 Etherで解放される。
-
ステップ7:引き出したEtherをWETHにラップし、1,700 WETHのフラッシュローンを返済し、約7.498 WETHを利益として保持。
結論
根本原因はattack()の捕捉成功フローにあります。EtherFreakersは、ターゲットトークンのエネルギー状態が確定する前にtargetChargeを支払います。その後、_transfer()が_beforeTokenTransfer()をトリガーし、支払い前の古いenergyOf(targetId)を読み取り、その一部をプールに分配します。これにより、freakerIndexが新しいEtherの裏付けなしに増加するため、同じターゲットエネルギーが支払いとプール入力の両方としてカウントされます。これは再入可能バグではなく、ビジネスロジックのインフレーションバグです。
将来的に同様のリスクを軽減するために:
-
同じトランザクションがまだ処理中である間に、転送フック内で経済的価値を可変状態から再計算することは避けてください。
-
転送フックが状態変数を読み取る場合は、実行順序が結果に影響しないことを確認してください(例:フックが実行される前に状態を確定し、後からではなく)。
Alkemi インシデント
概要
2026年3月10日、Ethereum上のAlkemiプロトコルが悪用され、約89Kドルの損失が発生しました。根本原因は会計エラーと不良なビジネスロジックです。不良な清算ロジックにより、誰でも同じトランザクション内で自身のポジションを清算して利益を得ることができます。さらに、会計エラーにより、清算中に攻撃者自身の担保の控除が上書きされ、攻撃者が意図したコストを負担せずに清算報酬を得ることができます。
背景
Alkemiは融資プロトコルです。借り手のポジションが過小担保になると、誰でもliquidateBorrow()を呼び出して負債の一部を返済し、割引で担保を差し押さえることができます。過剰な清算を防ぐために、プロトコルはトランザクションごとに返済可能な金額を3つの値の最小値に制限します。
- 借り手の現在の借入残高(
currentBorrowBalance_TargetUnderwaterAsset)。 - 清算割引を適用した後の借り手の担保でカバーできる最大返済額(
calculateDiscountedBorrowDenominatedCollateral())。 - アカウントを清算境界に戻すために必要な返済額(
calculateDiscountedRepayToEvenAmount())。これは市場がisSupportedの場合のみチェックされます。


脆弱性分析
根本原因は、Alkemiプロトコル(0x4822...a888)の不良なビジネスロジックと会計エラーです。借り手が未払いの借入がある限りcurrentBorrowBalance_TargetUnderwaterAssetは必然的に0より大きく、借り手が担保を持っている限りcalculateDiscountedBorrowDenominatedCollateral()が返す値も必然的に0より大きいため、AlkemiEarnPublicプロトコルは、与えられたローンが清算可能かどうかを判断するために、実質的にcalculateDiscountedRepayToEvenAmount()に依存しています。この関数では、清算が必要な負債額は、accountShortfall_TargetUserと呼ばれる変数に基づいて計算されるべきです。
しかし、実際の実装では、関数は代わりにグローバル変数closeFactorMantissaを使用して、返済が許可される負債額の上限を計算し、この値を返します。その結果、攻撃者は借入を行い、同じトランザクション内で直ちに自身のポジションを清算することができます。
さらに、liquidateBorrow()関数では、清算者と借り手が同じアドレスの場合、変数supplyBalance_TargetCollateralAssetとsupplyBalance_LiquidatorCollateralAssetは同じストレージスロットを指します。関数はその後、同じ初期残高に基づいて「削減された残高」と「報酬付き残高」を別々に計算し、その後、それらを順番に同じストレージスロットに書き戻します。削減された残高が先に書き込まれ、報酬付き残高が後から書き込まれるため、削減効果は上書きされて失われ、報酬結果のみが残ります。これにより、攻撃者は利益をさらに増幅させることができます。
攻撃分析
以下の分析は、トランザクション 0xa170...6d9d に基づいています。
-
ステップ1:攻撃者はBalancerから51e18 WETHのフラッシュローンを借入。
-
ステップ2:攻撃者は51e18 WETHをアンラップしてETHにし、Alkemiプロトコルに供給。
-
ステップ3:攻撃者はAlkemiから39.5e18 ETHを借入。
-
ステップ4:攻撃者は39.5395e18 ETHを使用して自身のポジションを清算。
-
ステップ5:攻撃者はAlkemiから93.5e18 ETHを引き出し。
-
ステップ6:攻撃者はフラッシュローンを返済し、43.4e18 ETHの利益を上げました。

結論
根本原因は、不良な清算ロジックにより、攻撃者が借入を行い、その後同じトランザクション内で自身のポジションを清算して利益を得ることができたことであり、不正確な会計ロジックが攻撃者の利益をさらに増幅させました。
将来的に同様のリスクを軽減するために:
- 借り手と清算人の残高更新については、プロトコルは一時的なメモリ変数に残高をコピーして別々に計算・書き戻すのではなく、ストレージ変数に直接操作すべきです。
MT インシデント
概要
2026年3月10日、BNB Chain上のデフレショナリートークンであるMT Tokenが悪用され、約242Kドルの損失が発生しました。根本原因は、取引制限ロジックの不良と、特殊な転送条件の不整合な処理です。デフレフェーズ中、コントラクトはプールの準備金が固定しきい値を超えた場合に購入操作を制限します。しかし、コントラクトは正確な金額(例:2e17 MT)の転送を紹介者バインディングアクションとして扱い、攻撃者が購入制限を回避して初期トークンを取得できるようにします。さらに、制限ロジックは不完全なパス検出(isBuy)に依存しており、ペアからルーターへの間接的なスワップルートをカバーできず、ホワイトリストチェックが重要な検証をさらにショートカットします。攻撃者は制限や手数料をトリガーすることなくMTトークンを蓄積し、管理された流動性操作と取引を通じてpendingBurnAmountを操作し、トークン価格が人為的に操作された異常な状態にプールを強制しました。
背景
MT TokenはBNB Chain上のデフレショナリートークンであり、取引制限が組み込まれています。デフレフェーズ中、コントラクトはプールのMT準備金が21,000e18を超えた場合に購入操作をブロックします。準備金がこのしきい値を下回ると、デフレフェーズが終了し、購入が再開されます。MT Tokenには紹介メカニズムも含まれています。正確に2e17 MTまたは1e17 MTの転送は、通常の取引ではなく、紹介者バインディングアクションとして扱われます。
脆弱性分析
根本原因はMTコントラクト(0x037E...b449)における購入制限設計の不良です。通常の状態では、攻撃者は制限フェーズ中にシードキャピタルとしてMTを取得できないはずです。しかし、コントラクトは正確に2e17 MTの転送を購入ではなく紹介者バインディングアクションとして扱っており、これにより攻撃者は購入制限を回避して2e17 MTを購入できます。

さらに、取引制限はisBuyブランチに依存して購入をブロックしますが、「ペアからルーターへ」のパスはカバーしていません。ルーターとペアの両方がホワイトリストアドレスであるため、そのような転送はホワイトリストチェックでショートカットされ、購入制限ロジックに到達しないため、攻撃者はルーターに購入をルーティングし、その後流動性を削除することでトークンを自身に抽出することでMTを取得できます。

攻撃分析
以下の分析は、トランザクション 0xfb57...fca6 に基づいています。
-
ステップ1:攻撃者は約358,681e18 WBNBをフラッシュローンしました。
-
ステップ2:攻撃者は2e17 MTを購入し、購入制限を回避しました。
-
ステップ3:攻撃者は4e12 WBNBと2e17 MTをペアに供給して流動性を追加しました。この転送は、上記と同様の理由で手数料徴収ロジックを回避しました。
-
ステップ4:攻撃者はペアからルーターへ約10,000,000e18 MTトークンを購入し、購入制限と手数料徴収ロジックの両方を回避しました。
-
ステップ5:攻撃者は流動性ポジションの半分を削除し、その過程でルーターが保持していたすべてのMTトークンを抽出してから、回復したMTを売却してWBNBに交換しました。このステップでは、
pendingBurnAmountは約9,000,000e18に操作されました。
-
ステップ6:攻撃者は再び約10,000,000e18 MTトークンを購入し、プールのMT準備金を約6,756,516e18に引き下げました。これは
pendingBurnAmountよりも低くなりました。
-
ステップ7:攻撃者は残りの流動性ポジションの半分を削除し、購入したMTトークンを引き出し、その後
distributeDailyRewards()を呼び出してプールからMTを燃焼しました。その結果、MT準備金は21,000e18に削減されました。
-
ステップ8:攻撃者はすべてのMTを約1,198e18 WBNBに交換し、フラッシュローンを返済して利益を確定しました。
結論
このエクスプロイトは、攻撃者が正確にBINDING_AMOUNTのMTトークンを購入することで購入禁止を回避できた、不正確な取引制限によって引き起こされました。MTトークンを取得した後、攻撃者は流動性を追加し、ルーターにMTを購入させ、最後に流動性を削除してトークンを回収することで、手数料徴収ロジックと購入制限の両方をさらに回避することができました。攻撃者はその後、売却操作を通じてpendingBurnAmountを蓄積し、燃焼を実行してプール準備金を異常な状態にし、操作された価格でMTを売却して利益を得ることができるようにしました。
将来的に同様のリスクを軽減するために:
- 転送セマンティクスと取引ロジックの厳密な分離を強制してください。
AAVE 担保清算インシデント
概要
2026年3月11日、AAVEはEthereum上で2,100万ドルの不正確な清算を受け、約1.01Mドルの損失が発生しました。根本原因はwstETHの不正なオラクル価格であり、本来健全であったポジションが過小担保状態になりました。その結果、ユーザーのポジションは清算され、財務的損失が発生しました。
背景
AAVEは、wstETHのようなラップされた資産を価格設定するためにオラクルアダプターを使用します。アダプターCAPO(Capped Price Oracle)は、ベースのETH/USD価格に変換比率(1 wstETHがどれだけのETHに相当するか)(getRatio())を乗算してwstETHの価格を導出します。比率の操作を防ぐために、CAPOはスナップショットベースの成長キャップを適用します。
maxRatio = snapshotRatio + maxGrowthPerSecond x (currentTime - snapshotTimestamp)
そして、価格設定中にgetRatio()の出力をクランプします(currentRatio > maxRatioの場合、maxRatioを使用)。このメカニズムは、比率と結果的な価格の最大上方ドリフトを効果的に制限します。
脆弱性分析
根本原因は、CAPOオラクルアンカー構成(0xe1D9...61Ef)における時間と比率の不一致でした。スナップショットタイムスタンプとスナップショット比率が設定されましたが、スナップショット比率は実際のwstETH/ETH比率よりも低く設定されていました。その結果、アダプターが計算したmaxRatioはライブ比率を下回り、getRatio()を下方にクランプし、wstETH/USDオラクル価格を体系的に過小評価しました。この抑えられた担保評価は、wstETHを担保として使用するポジションのヘルスファクターを低下させ、本来健全なアカウントが不正に不健全と分類され、清算される原因となりました。


攻撃分析
以下の分析は、トランザクション 0x9064...8a9c に基づいています。
-
ステップ1:清算者は約6304e18 WETHをフラッシュローンし、借り手を清算しました。
-
ステップ2:清算者はフラッシュローンを返済し、清算を完了しました。
結論
この清算は、不正確なオラクル価格設定によって引き起こされ、本来健全であるべき借り手を不健全な状態に誤って押しやり、それによってポジションの清算を引き起こしました。
将来的に同様のリスクを軽減するために:
-
重要なパラメータは、更新前に正確性を確認してください。
-
実装に検証チェックを追加し、不正なパラメータを拒否し、不正な設定が正常に適用されるのを防いでください。
Planet Finance インシデント
概要
2026年3月11日、Planet FinanceがBNB Chainで悪用され、推定10Kドルの損失が発生しました。根本原因は、プロトコルが借り手の保存された借入残高の増加を誤って発生利息として扱い、攻撃者が繰り返し借入を行い、割引決済をトリガーして記録された負債を過小評価できるようにしたことです。
背景
Planet Financeは、借り手が金利割引で返済できる融資プロトコルです。割引は段階的であり、ユーザーのステーキングされたGAMMAと他の資産のステーキングされた価値の比率によって決定されます。この比率が高いほど、返済割引も高くなります。割引スケジュールは3つのティアで構成されており、0%(最小)から50%(最大)の範囲です。
脆弱性分析
根本原因は、changeUserBorrowDiscount()で借り手の割引を決済する際に、プロトコル(0x4c9E...F467)が借り手の保存された借入残高の増加を誤って新規発生利息として扱い、本来発生利息にのみ適用されるべき割引が新規借入元本に誤って適用され、借り手の記録された負債が不適切に減少したことです。攻撃者はborrowとchangeUserBorrowDiscountのループを繰り返すことで過剰な割引を蓄積でき、オンチェーンで記録された負債が実際の借入額よりも一貫して低くなり、最終的にその差異から利益を得ることができました。


攻撃分析
以下の分析は、トランザクション 0x5f45...5ec9 に基づいています。
-
ステップ1:攻撃者は200,000e18 USDTをフラッシュローンしました。
-
ステップ2:攻撃者は5,000e18 USDTを使用してWBNBを購入し、その後取得したWBNBを使用して約8,726,524e18 GAMMAを購入しました。
-
ステップ3:攻撃者はまず、取得したGAMMAすべてをgGAMMA市場にステーキングし、残りのUSDTを担保として供給しました。これにより、返済割引が5%に増加し、その後の借入が可能になりました。
-
ステップ4:攻撃者は
borrowとupdateUserDiscountを繰り返し呼び出し、記録された負債を継続的に削減しました。
-
ステップ5:攻撃者は最終的に負債を返済し、担保を償還し、利益を確定しました。
結論
このインシデントは、Planet FinanceのchangeUserBorrowDiscount()における不良な割引決済ロジックによって引き起こされました。これは、借り手の保存された借入残高の増加を新規発生利息として誤って扱い、その差額に利息割引を適用します。攻撃者はborrowの後にupdateUserDiscountを繰り返し呼び出すことで、記録された負債を過小評価し、最終的に実際の負債よりも少ない額を返済して利益を抽出することができます。
将来的に同様のリスクを軽減するために:
- 融資プロトコルにおいて、利息と新規借入を区別してください。
AM インシデント
概要
2026年3月12日、BNB Chain上のデフレショナリートークンであるAM Tokenが悪用され、総損失額は約131Kドルと推定されました。AM Tokenはデフレメカニズムを実装しており、各売却で流動性プールから追加の燃焼がトリガーされ、トークンが永続的に削除されて総供給量が削減されます。しかし、燃焼は即座には実行されず、代わりに全売却額がtoBurnAmountとして記録され、実際の燃焼は次の売却に延期されます。この遅延により、記録と実行の間にウィンドウが作成され、その間に攻撃者はAMを買い戻して、プールのAM準備金をtoBurnAmountまで縮小させることができます。次の売却で遅延された燃焼がトリガーされると、AM準備金全体が消去され、価格が極端なレベルまで上昇し、攻撃者はAMを利益のために売却できるようになります。
背景
AM TokenはBNB Chain上のデフレショナリートークンです。各売却時に、コントラクトはスワップに関与したAMの金額をtoBurnAmountとして記録し、次の売却時にその記録された金額を流動性プールから燃焼します。実質的には、売却はプールのAM準備金を削減する遅延燃焼をトリガーします。さらに、燃焼を実行する前に、プロトコルは蓄積されたtotalTokenFeeをUSDTにスワップし、その手数料配分ロジックに従って分配します。
脆弱性分析
根本原因は、トークン(0x27f9...213f)の売却ロジックが、スワップされた全AM金額をtoBurnAmountとして蓄積し、次の売却時にAM/USDTペアからトークンを削除してpool.sync()を呼び出して準備金を更新することで、実際の燃焼を実行することです。この設計により、攻撃者はプールAM準備金を操作し、オンチェーン価格を歪め、アービトラージを通じて利益を得ることができます。


攻撃分析
以下の分析は、トランザクション 0xd0d1...f859 に基づいています。
-
ステップ1:攻撃者は約27,265,119e18 USDCと約361,710e18 WBNBをフラッシュローンし、それらを約100,423,811e18 USDTにスワップしました。
-
ステップ2:攻撃者は約5,062e18 AMトークンをUSDTにスワップし、これによりコントラクトの記録された
toBurnAmountが約4,303e18に操作されました。
-
ステップ3:攻撃者はUSDTをAMトークンにスワップし、プールの
AM準備金を約4,303e18まで低下させました。
-
ステップ4:攻撃者は6 wei AMをプールに転送し、売却パスの燃焼ロジックをトリガーしました。その結果、コントラクトはプールから全AM残高を燃焼し、AM準備金を0まで低下させました。注:プロトコルは、燃焼を実行する前に、まず蓄積された手数料をUSDTにスワップしようとします。この手数料変換パスも売却ブランチの燃焼ロジックをトリガーします。燃焼が実行され、AM準備金が0に達した後、手数料スワップは失敗します。try/catchでラップされているため、失敗はトランザクションをロールバックしません。代わりに、実行は継続され、手数料アキュムレータは0にリセットされます。

-
ステップ5:攻撃者は
pool.sync()を呼び出し、残りのUSDTと1 wei AMをプールに転送しました。両方のトークンが同時に転送されたため、コントラクトはこれをaddLiquidityとして扱い、toBurnAmountは蓄積されませんでした。AM準備金は7に更新されました。

-
ステップ6:攻撃者は残りのAMトークンをUSDTにスワップしました。このスワップ中に、AMをペアに転送すると売却パスの燃焼ロジックがトリガーされ、AM準備金は1に減少しました。さらに、ステップ4で
totalFeeAmountが0にリセットされていたため、手数料からUSDTへの変換はもはや実行されず、攻撃者は操作された価格でAMを売却することができました。
-
ステップ7:攻撃者はフラッシュローンを返済し、残りの利益を確定しました。
結論
このインシデントは、AM Tokenの不良な燃焼メカニズムによって引き起こされました。これは、各売却のスワップに関与したAMをtoBurnAmountとして蓄積し、次の売却時にpool.sync()を呼び出しながらAM/USDTペアからその金額を燃焼します。これにより、攻撃者はペアのAM準備金を極端なレベルまで操作し、操作された価格でAMを売却してUSDTを空にすることができます。
将来的に同様のリスクを軽減するために:
- トランザクションあたりの最大燃焼額を制限し、燃焼がトリガーされる頻度をレート制限することで、攻撃者が短期間でプールトークン準備金の大部分を消費することを防ぎます。
DBXen インシデント
概要
2026年3月12日、EthereumおよびBNB Chain上のバーン・トゥ・アーン(burn-to-earn)プロトコルであるDBXenが悪用され、総損失額は約149Kドルとなりました。根本原因は、_msgSender()とmsg.senderの間の不整合です。burnBatch()がforwarderを介して呼び出されると、燃焼されたXEN量は_msgSender()(攻撃者が制御)の下に記録されますが、サイクル記録はmsg.sender(forwarder)で更新されます。この分割により、攻撃者は古いサイクル記録に対して報酬と手数料を請求でき、異常に大きな支払いにつながります。
背景
DBXenはバーン・トゥ・アーンプロトコルです。ユーザーはXENトークンを燃焼して、DXN報酬と蓄積されたプロトコル手数料のシェアと交換します。主要なメカニズムはサイクルで機能します。ユーザーがburnBatch()を呼び出すと、2つのことが起こります。 (1) 燃焼されたXEN量は、呼び出し元のアドレス(_msgSender()で識別)の下に記録されます。(2) XENコントラクトはDBXenにonTokenBurned()を介してコールバックし、呼び出し元のサイクル記録(燃焼サイクルとlastFeeUpdateCycle)を現在のサイクルに更新します。
報酬と手数料はupdateStats()を介して決済されます。報酬は、ユーザーの燃焼サイクルにおける総燃焼XENに対するユーザーのシェアに比例します。手数料は、ユーザーの最後の記録サイクル以降に蓄積された累積プロトコル手数料に基づいています。両方の計算は、ユーザーのサイクル記録が最新であることに依存します。




脆弱性分析
根本原因は、DBXenプロトコル(0xf5c8...2abd)における不良なビジネスロジックです。_msgSender()関数は、msg.senderがforwarderであるかどうかをチェックします。もしそうであれば、calldataの最後の20バイトを返します。この返された値は、forwarderコンテキストで任意に制御できます。しかし、burnBatch()はmsg.senderが保持するXENを直接燃焼します。その結果、攻撃者はforwarderを介してburnBatch()を呼び出すことができ、プロトコルがforwarderが保持するXENを燃焼し、両方のforwarderの燃焼サイクル記録と手数料更新サイクル記録を現在のサイクルに更新させることができます。同時に、プロトコルは_msgSender()に対応するアドレスの下に燃焼されたXEN量を記録します。
その後、攻撃者はclaimFees()を呼び出し、updateStats()をトリガーします。_msgSender()アドレスのサイクル記録は更新されなかったため(燃焼サイクルとlastFeeUpdateCycleの両方が0のまま)、updateStats()は現在のサイクルで報酬を計算し、サイクル0以降に蓄積された手数料を計算します。これはプロトコルの全手数料履歴をカバーします。その後、攻撃者はclaimFees()とclaimRewards()を呼び出して利益を得ます。

攻撃分析
以下の分析は、トランザクション 0x914a5a...b808bc37 に基づいています。
-
ステップ1:攻撃者は最初に
ForwarderコントラクトのregisterDomainSeparator()関数を呼び出し、後続のForwarder.execute()呼び出しを有効にしました。 -
ステップ2:攻撃者はUniswap V2プールで0.14e18 ETHを13,900,000,000e18 XENにスワップしました。
-
ステップ3:攻撃者は13,900,000,000e18 XENを
Forwarderコントラクトに転送しました。 -
ステップ4:攻撃者は
Forwarder.execute()を使用して、DBXenがForwarderが保持する13,900,000,000e18 XENを支出することを承認しました。 -
ステップ5:攻撃者は
Forwarder.execute()を使用してDBXen.burnBatch()を呼び出し、13,900,000,000e18 XENを燃焼しました。燃焼量はアドレス0x425D3eC2DCeBE2c04bA1687504D43AFC6be7328dの下に記録されましたが、燃焼実行中、XENはonTokenBurned()を介してDBXenにコールバックし、Forwarder上の関連サイクル記録を更新しました。
-
ステップ6:攻撃者は
Forwarder.execute()を使用してDBXen.claimFees()を呼び出し、65.36e18 ETHを取得しました。 -
ステップ7:攻撃者は
Forwarder.execute()を使用してDBXen.claimRewards()を呼び出し、2,305.4e18 DXNをミントしました。
結論
このインシデントの根本原因は、DBXenプロトコルが_msgSender()とmsg.senderを不整合に使用したことです。これらの2つの値が異なる可能性があるため、プロトコルの内部会計が不整合になり、攻撃者がその差異を悪用して利益を得ることができました。
将来的に同様のリスクを軽減するために:
- すべてのロジックパスで一貫して
_msgSender()を使用するか、msg.senderに依存する操作と_msgSender()に依存する会計が常に同じアドレスを参照することを確認してください。
Goose Finance インシデント
概要
2026年3月15日、BNB Chain上のイールドファーミングプロトコルであるGoose Financeが悪用され、約8Kドルの損失が発生しました。根本原因はStrategyGooseEggのシェア価格設定順序の欠陥です。deposit()は、収穫された報酬を会計に決済する前にシェアをミントするため、シェア価格設定に使用される総資産の分母にはこれらの報酬が含まれず、真の値よりも低くなります。これにより、預金者は本来よりも多くのシェアを受け取ります。withdraw()が呼び出されると、報酬の収穫がトリガーされ、総資産が増加するため、各シェアの価値が高まります。単一トランザクションでデポジットとウィズドローをループさせることで、攻撃者は繰り返し過剰価格のシェアをミントし、それを修正された(より高い)価値で償還し、その差額を利益として抽出しました。
背景
Goose FinanceはBNB Chainのイールドファーミングプロトコルであり、ユーザー資金はVaultからStrategyに流れ、そこでMasterChefにステーキングされてEGG報酬を獲得します。
このインシデントに関連するコンポーネントは次のとおりです。
-
VaultChef(0x3f64...): ユーザーポジションを追跡し、StrategyGooseEggに資金を転送します。 -
StrategyGooseEgg(0x0980...):sharesTotalとwantLockedTotalで戦略レベルの会計を維持します。 -
MasterChef(0xe70e...): ステーキングされた資産を受け取り、EGG報酬を支払います。 -
WrappedEgg(0xb815...): EGGを1:1でWEGGにラップしてステーキングします。
運用上、デポジットはVaultChefからStrategyGooseEggにルーティングされ、その後MasterChefにステーキングされます。ウィズドローはVaultChefから開始され、戦略によって実行されます。
シェア価格設定の重要な会計上の期待は、価格設定時に戦略資産の合計(ステーキングされた元本と戦略が既に保持している未使用報酬)を反映することです。しかし、StrategyGooseEggでは、deposit()は_farm()が未使用資産をwantLockedTotalに決済する前にシェアをミントしますが、withdraw()はMasterChefからの報酬収穫をトリガーできます。この順序が以下の分析の脆弱性の基盤です。


脆弱性分析
根本原因は、StrategyGooseEgg(0x0980...b26b)における報酬収穫とシェア価格設定の間の会計の同期ずれです。
StrategyGooseEggでは、シェア価格設定はwantLockedTotalを分母として使用します。shares = deposit * sharesTotal / wantLockedTotal。これが公正であるためには、wantLockedTotalは戦略が実際に保持しているすべての資産(契約に未使用で残っているEGG報酬を含む)を反映する必要があります。しかし、deposit()は_farm()が未使用報酬をwantLockedTotalに決済する前にシェアをミントします。これは、分母に未計上の報酬が含まれず、真の総資産よりも低くなることを意味し、預金者が本来よりも多くのシェアを受け取る原因となります。
さらに、withdraw()はMasterChef.withdraw()を呼び出し、これはステーキングされた元本と未払いEGG報酬を戦略に返します。戦略の会計は要求された_wantAmtをwantLockedTotalから差し引くだけであり、収穫された報酬は戦略の残高に残り、wantLockedTotalに反映されません。これにより、実際の保有資産と記録されたwantLockedTotalの間のギャップが広がり、後続のdeposit()シェア価格設定がさらに不正確になります。
攻撃分析
以下の分析は、トランザクション 0x86efdf...ce316223 に基づいています。
-
ステップ1:攻撃者は2つのPancakeペアからEGGをフラッシュ借入しました。
-
ステップ2:最初のデポジット(10,170,000e18 EGG)を
VaultChef/StrategyGooseEggに行いました。 -
ステップ3:最初のウィズドロー(12,593,884e18 EGG)は
MasterChefから報酬を収穫しました。359,561e18 EGGがStrategyGooseEggに転送され、未使用/未計上資産(R > 0)として残りました。 -
ステップ4:2回目のデポジットは、ウィズドローされた資本(12,593,884e18 EGG)を再利用しました。シェアは未使用資産が決済される前に価格設定されたため、これが過剰ミントステップです。
-
ステップ5:2回目のウィズドロー(12,826,027e18 EGG)は、過剰ミントされたシェアからの利益(つまり、ステップ4のデポジット入力より232,143 EGG多い)を実現しました。
-
ステップ6:攻撃者はフラッシュスワップを返済し、純利益を確保しました。
結論
このエクスプロイトは、StrategyGooseEggのシェア価格設定順序の欠陥に起因します。deposit()は_farm()がwantLockedTotalを更新する前にシェアをミントし、withdraw()は一時的に未使用で未計上の報酬をMasterChefから収穫することができます。これにより、デポジットは古い分母に対してミントされ、後で更新された資産に対してウィズドローできます。
将来的に同様のリスクを軽減するために:
-
報酬を決済し、シェアミントとシェアバーンの両方の計算前に会計を更新してください。
-
単一の
totalAssets(ステーキング済み+未使用)に対して、正確な計算ポイントでシェアを価格設定してください。 -
未収報酬がゼロでない条件での
shares_minted <= D * S / (A + R)の不変テストを追加してください。
BlockSecについて
BlockSecは、フルスタックのブロックチェーンセキュリティおよび暗号コンプライアンスプロバイダーです。当社は、顧客がコード監査(スマートコントラクト、ブロックチェーン、ウォレットを含む)、リアルタイムでの攻撃傍受、インシデント分析、不正資金追跡、およびプロトコルとプラットフォームのライフサイクル全体にわたるAML/CFT義務の遵守を支援する製品とサービスを構築しています。
BlockSecは、権威あるカンファレンスで複数のブロックチェーンセキュリティ論文を発表し、いくつかのゼロデイ攻撃を報告し、複数のハッキングを阻止して2,000万ドル以上を救済し、数十億ドルの暗号通貨を確保しています。
-
公式ウェブサイト:https://blocksec.com/
-
公式Twitterアカウント:https://twitter.com/BlockSecTeam



