先週(2026/08/10 - 2026/08/16)は、以下の5件の注目すべきセキュリティインシデントが発生し、合計損失額は約4,700万ドルに上りました。
| 日付 | インシデント | タイプ | 推定損失額 |
|---|---|---|---|
| 2026/08/10 | Coinsbuy | 秘密鍵の漏洩 | ~$7.9M |
| 2026/08/10 | 不明なホエールウォレット | 秘密鍵の漏洩 | ~$25M |
| 2026/08/12 | Harmony | バリデーション上の問題 | 不明* |
| 2026/08/13 | Kite | 秘密鍵の漏洩 | ~$14M |
| 2026/08/15 | Fox | ビジネスロジックの欠陥 | ~$117K |
*Harmonyは、確認済みの第一波としてONEが40億トークンミントされたことと、より広範な再構築により約3.01兆ONEが偽造され、そのうち約2.385兆ONEが転送されたと報告しています[1]。インシデント前の価格である約0.001183ドルで計算すると、偽造された金額の名目上の価値は約35.6億ドルに相当しますが、これはONEの総供給量の約200倍に達し、トークンの市場総額を大幅に超えているため、実現可能でも、実現した損失として確認されたものでもありません。Harmonyはその後、チェーンを攻撃前のチェックポイントまでロールバックし、偽造された状態を破棄しました[2]。したがって、Harmonyは総損失額から除外されています。
選定理由
- Harmony: チェーン実装のリプレイ保護の欠陥により、Harmonyエコシステム全体で大規模な不正なネイティブトークンの発行が可能になったため選出されました。調査の過程で、ステーキング前のクォーラム検証における別の脆弱性が特定されましたが、この脆弱性が実際のエクスプロイトに関与したかどうかは確認されていません。
Best Security Auditor for Web3
Validate design, code, and business logic before launch
今週の注目: Harmony
今週Harmonyを取り上げるのは、この欠陥がアプリケーションコントラクトではなくチェーン実装そのものに存在していたためです。これは、レイヤー1全体の基盤資産を膨張させる可能性があるという点で、異例なほど影響度の高い失敗形態です。
2026年8月12日、シャーディング型のレイヤー1ブロックチェーンであるHarmonyは、クロスシャードレシートのリプレイの欠陥により、ネイティブトークンであるONEの不正なミントを被りました。宛先シャードは、ソースコミッティーの署名でカバーされていないフィールドを使用して、既に消費されたレシートを識別していたため、攻撃者はそれらのフィールドのみを変更することで、正当かつ以前にクレジットされたレシートを再提示し、ソースシャード側で対応するデビットが発生することなく、再度クレジットさせることができました。Harmonyは、確認済みの第一波としてONEが40億トークンミントされたことと、より広範な再構築により約3.01兆ONEが偽造され、偽造ミントウォレットにより約2.385兆ONEが転送されたこととの整合性を調整していました。これらのいずれも実現した損失として確認されたものではなく、最終的な影響はロールバックおよび取引所側の調整に左右される可能性があります[1][2]。調査の過程で、Harmonyはステーキング前のクォーラム検証における別の欠陥を特定しましたが、今回のエクスプロイトがこれに依拠していたかどうかは確認していません。
背景
Harmonyはシャーディング型のレイヤー1ブロックチェーンです。各シャードは独立した状態を維持しているため、ソースシャードは宛先シャード上のアカウントを直接変更することはできません。シャード間で価値を移動させるために、Harmonyは非同期のレシートベースの設計を採用しています。ソースシャードが送信者からデビットしてクロスシャードレシートを発行し、宛先シャードが後で受信者にクレジットするという仕組みです。
クロスシャードレシートは転送そのものを記録します:
type CXReceipt struct {
TxHash common.Hash
From common.Address
To *common.Address
ShardID uint32
ToShardID uint32
Amount *big.Int
}
宛先シャードは、レシート単体を信頼するわけではありません。レシートはCXReceiptsProofの中を伝わり、それにはマークルプルーフ、ソースブロックのヘッダー、そのヘッダーに対するソースコミッティーのコミット署名が含まれています:
type CXMerkleProof struct {
BlockNum *big.Int
BlockHash common.Hash
ShardID uint32
CXReceiptHash common.Hash
ShardIDs []uint32
CXShardHashes []common.Hash
}
type CXReceiptsProof struct {
Receipts CXReceipts
MerkleProof *CXMerkleProof
Header *block.Header
CommitSig []byte
CommitBitmap []byte
}
通常の検証パスでは、署名済みのソースヘッダーとそのコミッティー署名に対してプルーフを検証します:
VerifyIncomingReceipts()
-> IsSpent()
-> ValidateCXReceiptsProof()
-> VerifyHeaderSignature()
-> verifySignature()
-> DecodeSigBitmap()
-> IsQuorumAchievedByMask()
-> aggSig.VerifyHash()
ソースシャードはデビットを一度だけ実行するため、宛先シャードは各クロスシャードレシートが一度だけ消費されることを保証しなければなりません。
脆弱性分析
クロスシャード決済パスには2つの問題が含まれていました。消費済みレシートの識別方法におけるリプレイ保護の弱点と、ステーキング前のクォーラム検証の弱点です。
クロスシャードレシートのリプレイ
リプレイ保護はレシートの「消費済み」マーカーを記録・検索していましたが、そのキーはマークルプルーフの2つの可変フィールドから生成されていました:
CXMerkleProof.ShardID
CXMerkleProof.BlockNum
Bloomハードフォークにより、2026年7月13日のエポック2964でメインネットでこの点が強化され、IsCXMerkleProofReplayFixEpochによってゲートされました[3]。署名済みのHeader.Epoch()がこのエポック以降であるプルーフについては、IsSpent()およびWriteCXReceiptsProofSpent()は、これら2つのフィールドではなく署名済みのソースヘッダー(Header.ShardIDおよびHeader.Number)から消費済みマーカーのキーを生成するようになりました。ただし、この強化されたキー生成方式が遡及的に適用されることはありませんでした。Header.Epoch()がフォーク以前であるプルーフについては、両関数とも従来のMerkleProof.ShardIDおよびMerkleProof.BlockNumへのフォールバックが維持されており、それらのエポックにおいてはValidateCXReceiptsProof()がこれらを署名済みヘッダーに結び付けることは一度もありませんでした。
これら2つのフィールドは、ソースのHeaderのみをカバーするコミット署名の対象外です。Headerを変更すればVerifyHeaderSignature()は失敗しますが、MerkleProof.ShardIDまたはMerkleProof.BlockNumを変更してもチェックは一切破られません。ヘッダー署名も、これらのエポックにおいてそれらをHeaderに結び付けることが一度もなかったプルーフ検証も、破られないのです。従来の消費済みマーカーのキーがこれらの未認証フィールドから生成されていたため、レシートのリプレイ保護上の識別情報は、プルーフの他の部分を認証する署名から切り離されていました。同じ署名済みヘッダーとレシートを持つが、MerkleProof.ShardIDまたはMerkleProof.BlockNumの値が異なる2つのプルーフは、消費済み追跡の目的上、別個のものとして扱われていたのです。

ステーキング前のクォーラムチェック
2つ目の欠陥は、ステーキング前のクォーラム検証に影響を与えました。uniformVerifier.IsQuorumAchievedByMask()のロジックは、しきい値を以下と比較していました
len(mask.Publics)
これを署名者の数として扱っていました。しかし、mask.Publicsはシャードおよびエポックのコミッティーの公開鍵の全リストであり、実際に署名したバリデーターの集合ではありません。実際に署名した集合は署名者ビットマップによって表現されています。その結果、空の署名者ビットマップであってもクォーラムしきい値をクリアできてしまう可能性がありました。なぜなら、このチェックが有効なビットマップのビット数ではなくコミッティーのサイズを測っていたためです。これに単位元(全ゼロ)の集約BLS署名を組み合わせることで、ステーキング前時代のソースヘッダーが十分なクォーラムを備えているように見せることが可能になり得ました。

攻撃分析
攻撃者は、ハードフォーク以前のソースシャードブロックからの、正当かつ既に処理済みのクロスシャードレシートから開始し、未認証のプルーフ識別情報のみを変更することでそれをリプレイしました。偽造されたONEは4つのエクスプロイター・ウォレットにミントされました。以下の分析はトランザクション0xf3d4e8b1...8242c7fおよび0x9a756ef9...b0a4d678に基づいています。
-
ステップ1: 攻撃者は、ハードフォーク以前のソースシャードブロックから有効な過去の
CXReceiptsProofを取得しました。このプルーフには有効なレシート、有効なソースブロックヘッダー、有効なソースコミッティーのコミット署名が含まれていました。 -
ステップ2: 宛先シャードは既にこのレシートを一度消費し、マークルプルーフのフィールドから生成されたキーで消費済みマーカーを書き込んでいました。
-
ステップ3: 攻撃者は、未認証のプルーフ識別情報フィールドのみを変更し、署名済みヘッダーと署名でカバーされる全フィールドは手を加えないままにしました:
MerkleProof.ShardID MerkleProof.BlockNum -
ステップ4: 変更されたプルーフは、後の宛先シャードのブロックに着信レシートとして提出されました。
IsSpent()は変更されたフィールドから消費済みマーカーのキーを生成したため、以前のマーカーを見つけることができず、レシートは未消費に見えました。 -
ステップ5:
ValidateCXReceiptsProof()はそれでもこのプルーフを受け入れました。変更された識別情報フィールドは署名でカバーされていない一方で、認証対象の全フィールド(ヘッダーハッシュと発信レシートハッシュ、マークルプルーフのブロックハッシュとレシートハッシュ、レシートハッシュ、そしてコミット署名とビットマップ)は変更されないままだったためです。 -
ステップ6:
ApplyIncomingReceipt()が宛先シャード上で実行され、db.AddBalance(*cx.To, cx.Amount)により受信者に再度クレジットされました。元のクロスシャードトランザクションは既に一度だけ実行済みであったため、ソースシャード上での対応するデビットは発生せず、宛先シャード上でネイティブONEの膨張が生じました。
結論
プロジェクトが確認した根本原因は、プロトコルレベルのリプレイ保護の失敗でした。クロスシャードレシートの消費状態を示す識別情報が、署名済みのソースヘッダーではなく未認証のプルーフフィールドから生成されていたため、既に処理済みのレシートが再度クレジットされ得たのです。Harmonyはまた、ステーキング前のクォーラム検証における別の欠陥を確認しましたが、公開されている情報からは、攻撃者が今回それを利用したかどうかは確認できません。
パッチは両方のギャップを解消しています[4][5][6]。より広く言えば、チェーン実装は既に消費された状態を識別するために使用するすべてのフィールドを認証しなければならず、クォーラムの判断は実際に署名したバリデーターに基づいて行うべきであり、コミッティー全体に基づくべきではありません。
参考文献
- [1] Harmonyインシデントに関する最新情報
- [2] Harmonyのロールバック計画
- [3] Harmony Bloomハードフォーク (PR #5053)
- [4] コミット 61afbf6: CXレシート消費済みマーカーのキーを修正
- [5] コミット 7515262: クォーラムビットマップのカウント処理を修正
- [6] Harmony PR #5101
BlockSecについて
BlockSecは、フルスタックのブロックチェーンセキュリティおよび暗号資産コンプライアンスのプロバイダーです。当社は、プロトコルおよびプラットフォームのライフサイクル全体にわたって、コード監査(スマートコントラクト、ブロックチェーン、ウォレットを含む)の実施、攻撃のリアルタイムでの阻止、インシデントの分析、不正資金の追跡、AML/CFT義務の遵守を、お客様が実現できるよう支援する製品とサービスを構築しています。
BlockSecは、権威ある学会において複数のブロックチェーンセキュリティに関する論文を発表し、DeFiアプリケーションに対する複数のゼロデイ攻撃を報告し、2,000万ドル以上を救済するために複数のハッキングを阻止し、数十億ドル相当の暗号資産を保護してきました。
-
公式ウェブサイト: https://blocksec.com/
-
公式Twitterアカウント: https://twitter.com/BlockSecTeam



