
4分で読めます
偽のERC-20入金攻撃:偽装イベントログがインデクサーを騙す仕組み
2026年7月24日、Ethereum上のコントラクトが「0.29 ETHがあるアドレスに到着した」というログを出力しました。実際には、どこにも0.29 ETHは届いていません。トランザクションは成功し、ブロックは確定し、今やオンチェーンの記録には「送金が発生した」と書き残されています。
この乖離――チェーンが記録したことと、チェーンが実際に行ったことの間の落差――こそが攻撃のすべてです。取引所がハックされたわけではありません。領収書を信頼するように作られたシステムに対して、偽造の領収書が提出されただけなのです。
この手口自体は古く、研究者たちは偽入金の脆弱性を2021年のIEEE論文で文書化しており、CoinDeskも2020年に約10億米ドル分のトークンが露見していたと報じいます。注目に値するのは、それが存在するという事実ではありません。2026年版のコストがいかに低く、監視ダッシュボードの上ではいかに平凡に見えるかという点です。
トランザクションに実際含まれているもの
EOA(外部所有アカウント)がコントラクトを呼び出します。コントラクトは2つの内部トランザクションを生成し、1つのイベントログを書き込みます。攻撃者がリスクを負う金額は、ガス代だけです。
イベントログこそがペイロードです。その中身は次のとおりです。
Transfer (index_topic_1 address to, uint256 amount)
to: 0xC5518694Ef1A64eF0362eB5165A8A41e83Ff4C41
amount: 290000000000000000
名前ではなく、シグネチャを読んでください。
標準的なERC-20のTransferイベントはTransfer(address,address,uint256)で、送信者・受信者・金額の3要素からなり、最初の2つはインデックス化されます。ログには3つのトピックが入ります。
このイベントにはインデックス化されたパラメータが1つ、トピックが2つしかありません。fromが存在しないのです。それがトリックのすべてです。
本物の送金は、誰が送ったかを記録します。これが記録しているのは誰が受け取ったかだけです。何も送られていないからです。コントラクトは独自のイベントを定義し、それにTransferという名前を付け、トークン標準では決して生成されない形を与えました。そのトピックハッシュ(0x69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c...)はERC-20のシグネチャハッシュではありません。同じ名前をまとった、別のイベントなのです。
内部トランザクションがそれを裏付けるように見せかけます。どちらもTransferというラベルを持ち、どちらも0.29 ETHを運び、どちらもこのコントラクトを発生源としています。1つは偽造ログに記されたアドレスを指し、もう1つは一連の流れを開始したアカウントを指し戻します。うち1つはcallcodeで実行されます。callcodeは呼び出し元自身のコンテキストで借りたコードを実行する非推奨のオペコードで、正当な現代のコントラクトではほぼ絶滅しています。
トレースを肉眼で眺めれば、呼び出しを受けてETHを動かしたコントラクトに見えます。それを機械的に解析すれば、入金に見えるのです。
取引所がこれを入金扱いする理由
入金の計上はインデクシングの問題であり、インデクサーはパターンマッチャーです。入金パイプラインはチェーンを監視し、どのイベントが自社管理アドレスへの価値の到着を表すかを判断し、残高を計上します。その判断は通常、「Transferという名前のイベントが存在するか」「toフィールドが入金アドレスと一致するか」「金額がパース可能か」「トランザクションが成功したか」といった条件の組み合わせで下されます。
ここではそのすべてが真です。トランザクションは成功しています。イベントの名前はTransferです。受信者は一致します。金額は0.29 ETHとしてきれいにパースできます。
多くのパイプラインが決して行わない検証が、次の1つです。イベントのトピックハッシュはERC-20の標準シグネチャと一致するか、そしてその結果として残高変動は実際にステート上に存在するか。
イベント名でマッチさせていれば、何でも飲み込まされてしまいます。シグネチャハッシュでマッチさせ、残高と突き合わせて検証すれば、このトランザクションは無害になります。
そして後半が動きます。残高が計上されると、攻撃者はただちに引き出します。何の裏付けもない入金を当てにしてです。取引所は本物の資産を送ります。偽造入金は突合作業で検出されません。ほとんどの突合は数時間後にバッチで行われるためで、その頃には引き出しはすでに決済済みです。
スピードは付随物ではありません。スピードこそがプロダクトです。
2026年版が注意を要する理由
理由は3つあります。どれも単体では目新しいものではありません。
- コストはガス代だけです。資本は拘束されず、試行が失敗しても失うものはありません。つまり攻撃者は100の取引所に同じ手口を仕掛けられ、許容的なインデクサーが1つあれば足りるのです。
- 金額が小さいです。0.29 ETHでは大額送金アラートは作動しません。最初の試行の目的は利益ではなく、あなたのパイプラインがこれを入金扱いするかどうかの確認です。続く攻撃は、あなたの引き出し限度額が許す範囲に合わせて規模が決まります。
- オンチェーン上で読み取れます。すべての要素が公開され、確定済みです。脆弱性の悪用も、盗まれた鍵も、侵害されたエンドポイントもありません。あなたのログには何事もない平常の1日として記録されるでしょう。
運用上重要なのは最後の点です。痕跡を残さない攻撃の検出は難しいものです。これは完璧な痕跡を残しながら、それでも検出が難しい。痕跡が正しく見えるからです。
3つの検証
- イベント名ではなく、シグネチャハッシュで照合する。インデクサーはtopic0を正規のERC-20 Transferハッシュと比較し、ラベルが何であれ、それ以外は破棄すべきです。ここで説明した攻撃を止めるのは、このたった1つの変更です。
- イベントではなく、ステートに対して検証する。イベントは主張にすぎません。入金を計上する前に残高を問い合わせ、実際に動いたことを確認してください。イベントはインデクシングのための便宜であって、決済の証明として設計されたものではありません。それを証明扱いすること自体が根本的な誤りなのです。
- 入金計上と引き出しの間に時間を置く。確認ポリシーがどのようなものであれ、数秒前に計上された入金を使う最初の引き出しは、通常の引き出しとは別の経路を通るべきです。この攻撃は2つの事象が隣接していることに依存しています。それらを引き離すコストはあなたにとってごくわずかで、攻撃者にとってはスキーム全体を失うことになります。
これらの管理をゼロから設計するのではなく、本番環境で運用している事業者へ申し上げます。引き出しの承認は機能ではなくポリシーレイヤーです。それは承認フロー、しきい値、エスカレーションが既に存在する場所に置かれるべきであり、そこは同時に、誰が何を承認したかについての改変不可能な記録が書き込まれる場所でもあります。
持ち帰るべき教訓
7月24日、誰も何にも侵入しませんでした。コントラクトが自分自身についての一文を書き、その一文は、高速で読むソフトウェアに誤読されるように設計されていたのです。あなたの入金パイプラインは台帳の読み手ではありません。ドキュメントのパーサーであり、これまで黙って、ドキュメントが自らの内容について正直であると信じてきたのです。


