新たに発表された研究論文により、GitHubの「Verified」バッジはコミットハッシュが署名済みコンテンツを一意に識別することを保証しないことが明らかになりました。この事実は、ソフトウェアサプライチェーン全体でハッシュベースのセキュリティ制御を支えてきた根本的な前提を揺るがすものです。
Jacob Ginesin氏は、攻撃者が署名鍵を持たず、SHA-2を破らなくても、同一のツリー、同一のメタデータ、有効な署名を持ちながら、バイト単位では異なる2つ目のコミットを作成でき、それぞれが独立した「Verified」バッジを取得できることを実証しました。両者の違いはハッシュ値のみです。
研究チームはこの現象を「ハッシュチェーン可鍛性(hash chain malleability)」と名付けました。これは、1つの改変されたコミットが連鎖的に波及し、それ以降に続くすべての依存コミットのハッシュ値を変化させてしまう現象を表す言葉です。
これが可能になるのは、Gitの署名バイト列がコミットオブジェクトのハッシュ対象領域内に置かれているためです。そのため、署名にバイトレベルの変更を加えるだけでコミットハッシュは変化する一方、ツリーや親コミット、メッセージには一切手を加える必要がありません。
重要なのは、検証プロセスがペイロードに対して何らかの有効な署名が存在するかどうかしかチェックしておらず、それが唯一許容されるエンコーディングであるかどうかまでは確認していない点です。これが操作の余地を生んでいます。
Arxivの論文では、それぞれ異なる署名方式を狙った3つの異なる手法が詳細に説明されています。
注目すべきは、GitHubのサーバー側検証機構がこれら3つの手法すべてを受理してしまったことです。これは、DER正規化を強制しておらず、ハッシュ対象外のOpenPGPサブパケットを除去しておらず、正規形でないECDSAスカラー値も受け入れてしまうためです。
GitHubは「Verified」の記録をコミットハッシュに紐づけて保持しており、再評価を一切行わないため、改変されたコミットは元の署名鍵がローテーションされたり失効したりした後でも、Verifiedステータスを保持し続けます。
これはいくつかの下流リスクを生み出します。ハッシュ値をもとに悪意あるコミットをブロックするインシデント対応ツールは、攻撃者が内容の同一な「ゴースト」コミットを新たな未登録のハッシュで再プッシュすることで、気づかれないまま回避されてしまう可能性があります。
Nixpkgs、Goモジュール、GitHub Actionsをはじめ、依存関係をコミットハッシュに固定するシステムは、もはや成立しない一意性を前提としています。特にNixpkgsは、GPG署名と不変のハッシュ値の組み合わせに依存しているため、この問題の影響を受けやすいといえます。
SLSA Source TrackやSigstoreのGitsignといった再現可能ビルド・来歴管理フレームワークは、コミットハッシュを不変の信頼アンカーとして扱っています。しかし可鍛性攻撃は、そのアンカーを守るどころか複製してしまいます。偽造されたコミットは、それ自身の独立したVerifiedステータスを獲得してしまうからです。
Jacob Ginesin氏は責任ある開示の手順に従い、2026年1月にGNUおよびGitへ、2026年3月にGitHubへそれぞれ通知を行いました。しかし本記事執筆時点でも、この問題は未対応のままとされています。
提案されている緩和策には、S/MIMEエンベロープに対するDER正規化の強制、あらゆるID情報を導出する前段階でのハッシュ対象外OpenPGPサブパケットの除去、ECDSA署名のlow-s形式への正規化などが挙げられています。論文では、これらの変更は署名時点で当然のこととして扱うのではなく、ハッシュの一意性に依存するあらゆる利用者側で強制的に実施されるべきだと主張しています。
翻訳元: https://cyberpress.org/github-verified-badge-hashes-signed-commit/