Midnight の開発チームは日本時間 10 月 6 日 19 時台、ノードの新版 1.0.400 を GitHub で公開しました。台帳の部品を 8.1.3 に上げて重大度 critical のセキュリティ勧告 GHSA-wr7g-rr4v-jmj8 を直す版で、修正はプレビュー、プレプロッド、メインネットの 3 つのネットワークですでに動いていると説明しています。
Midnight node 1.0.400 リリースノート(GitHub)(GitHub)
つまり今回の公開は「これから入れる修正」ではなく、本番で先に入れた修正を後から公開した版です。勧告の中身は、ゼロ知識証明が確かめる値と、実際にコントラクトが実行する値が食い違いうるというもので、Midnight の秘匿コントラクトの根幹に関わります。この記事では、何が直ったのか、なぜ先に本番へ入れたのか、ノードを動かす人とアプリを作る人がそれぞれ何をすればよいのかを、リリースノートと勧告に書かれた範囲で整理します。
直したのは「証明の見え方」と「実行の見え方」のずれ
勧告のタイトルは「Q3 2026 Audit Issue C-3」で、9 月 21 日付の Midnight Ledger 9 の監査報告で見つかった指摘です。勧告は日本時間 10 月 2 日 3 時台に公開され、影響を受ける版を台帳 8.1.2 以前、修正版を 8.1.3 としています。CVSS 4.0 の評価は 9.2(Critical)です。
仕組みを噛み砕くと、次のようになります。Midnight のコントラクト呼び出しでは、台帳はゼロ知識証明を「有限体(ある素数 p で割った余りの世界)の値」に置き換えた形で検証します。一方、コントラクトの状態を動かす仮想マシン(VM)は、送られてきた元の値をそのまま使います。値 x と、x に p を足した値は、証明の側から見ると同じ値に縮みますが、VM の側では別のバイト列です。
勧告が挙げる例は、支払い済みの請求番号を集合(Set<Field>)に記録して二重払いを防ぐコントラクトです。攻撃者が x + p の形で同じ請求を出し直すと、証明は「同じ請求」として通り、VM は「まだ記録にない新しい番号」として支払ってしまう。64 バイトの上限の中で x + 2p、x + 3p と別名を作れるため、1 回分の権利で何度も払い出しを受けられる、というのが勧告の説明です。出金やトークン発行をこの形で守っている場合は、余分な出金や発行にもつながりうるとしています。
台帳 8.1.3 は、こうした「正規形でない」値をコントラクト呼び出しの中で受け付けないようにしました。勧告は修正の過程で見つかった隣接の問題も記載しており、そのうち長さ 0 の空命令(noop 0)を拒否する変更は、今回のリリースノートにも明記されています。
先に本番へ入れてから公開した理由
リリースノートの冒頭は、この版を「プレビュー、プレプロッド、メインネットにすでに展開済みのセキュリティ修正の公開版」と位置づけています。ランタイム(チェーン上の規則そのもの)は変えないバイナリだけの更新で、spec_version は 1_000_300 のまま、ガバナンスの手続きも不要です。
先に本番へ入れた理由は、勧告の性質を見ると分かります。勧告自身が「この情報から攻撃を組み立てるのは容易」として攻撃の難しさを低く評価しており、手順を公開してから各ノードが更新するまでの時間差は、そのまま攻撃の窓になります。勧告に収められた監査報告も、公開の前にコントラクト開発者へ非公開で知らせるよう求めていました。修正を先に行き渡らせてから中身を明かす順序は、こうした脆弱性で一般的な開示の手順です。
時系列も確認しておきます。勧告の公開は日本時間 10 月 2 日 3 時台で、メインネットで誰でもコントラクトを配備できる「パーミッションレス配備」が始まったのは同じ日の 16 時台でした(10 月 2 日の記事)。修正がメインネットに入った正確な日時はリリースノートには書かれていませんが、10 月 5 日の時点で 3 つのネットワークすべてで動いていると明記されています。
あわせて、1.0.300 で既知の問題とされていた「メインネットをゼロから同期するとブロック #1788979 で止まる」不具合も直りました(1.0.300 の記事)。止まっていたノードは、1.0.400 で再起動すれば同期をやり直さずに取り込みを再開できるとしています。
ノード運用者と開発者がすること
ブロックを作る運用者に求められているのは、全員が同じ台帳の版にそろえることです。台帳 8.1.3 のノードは、8.1.2 のノードが受け付けるコントラクト呼び出しの一部を「形式が正しくない」として拒否します。版が混在すると、同じ呼び出しを有効とみなすかどうかでブロック生成者の判断が割れるため、リリースノートはブロック生成者が一斉に切り替えるよう求めています。リセットは不要で、作業はノードのバイナリかイメージの入れ替えだけです。フルノードの運用者、とくにメインネットを最初から同期している人も対象に挙げられています。
アプリの開発者は、呼び出しの作り方を変える必要はありません。公式のコンパイラ(compactc)と midnight-js が出力する呼び出しには、今回拒否される形式は含まれないと開発チームは説明しています。
ただし、勧告には一つ注意書きがあります。新しく拒否するようになっても、すでにコントラクトの状態に保存された別名の値は直らない、という点です。Field 型の集合や対応表で払い出し・出金・発行を守っているコントラクトの管理者は、保存済みの状態に重複した記録がないかを確かめるよう勧告は求めています。
次に確かめたいのは、GitHub の勧告ページ GHSA-wr7g-rr4v-jmj8 の更新日時です。いまの日付は公開時の 10 月 1 日(UTC)のままで、既存コントラクトの点検結果や追加の対応が書き足されれば、ここが動きます。パーミッションレス配備のあとに出てきた払い出し型のコントラクトを使う場合は、利用の前に一度このページを開いておくと判断の材料になります。
ことば
- セキュリティ勧告(GHSA)— GitHub 上で公開される脆弱性の告知。識別子 GHSA-wr7g-rr4v-jmj8 は今回の指摘を指し、影響版・修正版・評価値・再現手順がまとまっています。
- 有限体と「正規形」— ある素数で割った余りだけを扱う数の世界。同じ余りになる値は何通りも書けるため、0 以上 p 未満の書き方だけを正規形として認めるのが今回の修正の考え方です。
- spec_version — チェーン上で動くランタイムの版番号。今回は変わらないため、ノードの入れ替えだけで済み、ガバナンスの投票は要りません。
一次ソース / 関連リンク
セキュリティ勧告 GHSA-wr7g-rr4v-jmj8(midnight-ledger)(GitHub)
GitHub
