flawopen.com/ディレクトリ/226
Marimo GHSL-2026-226:テストリリースワークフローの TOCTOU
同じ秒に発生するタイムスタンプ競合により、Pull Request の更新がメンテナーのテストリリース承認をすり抜け、TestPyPI と npm の公開ジョブへ到達する可能性がありました。脆弱なワークフローは削除され、CVE は割り当てられていません。
研究室の責任者が特定のサンプルを承認しますが、研究室は時計の秒だけを確認します。同じ秒にサンプルを差し替えると、交換品も承認済みに見えてしまいます。Marimo のワークフローは Pull Request のコミットで同じ誤りを起こし、ビルドしたパッケージを公開ジョブに渡しました。
主要な概念と専門用語
TOCTOU- Time-of-check to time-of-use:セキュリティ確認後、リソースが使われる前にそのリソースが変化する問題です。
OIDC 公開- CI ジョブが GitHub Actions の ID をパッケージレジストリの短期資格情報と交換し、長期パスワードを保存せずに公開します。
ワークフローアーティファクト- GitHub Actions のジョブ間で渡されるファイル群です。後続ジョブは、信頼できないワークフローのアーティファクトを未信頼入力として扱う必要があります。
GHSL-2026-226- この Marimo ワークフローの欠陥に対する GitHub Security Lab のアドバイザリ ID です。CVE は割り当てられていません。
CWE-367 / CWE-829- アドバイザリは検査と使用の間の競合、および信頼されない制御領域の機能実行を指摘しています。
フレームワーク対応
ステップ・バイ・ステップの攻撃フロー
メンテナーがテストリリースを承認
メンテナーが Pull Request にコメントし、Marimo のテストリリースワークフローを起動します。承認はレビューした Pull Request の状態に対して行われる想定です。
同じ秒の間に Pull Request の head が変わる
ワークフローは pushed_at とコメントの created_at を整数秒に変換して比較します。同じ秒の push は同じ値になります。
脆弱なチェックが同じ値を受け入れる
削除されたワークフローは、コメント時刻より厳密に後の pushed_at だけを拒否していました。同じ値は通過し、更新後のコミットが記録されました。
未信頼コードがパッケージ成果物を作る
ジョブはそのコミットを checkout し、リポジトリ管理下の action とビルドスクリプトを実行しました。成果物はアップロードされ、信頼できるコミットから再ビルドされずに後続の公開ジョブで使われました。
公開権限が未信頼の出力に及ぶ
TestPyPI と npm のジョブは OIDC 公開権限を使っていました。アドバイザリは成果物が公開に到達し得たと説明していますが、実際のパッケージ侵害は報告していません。
ソースコード比較:脆弱 vs 堅牢化
GHSL-2026-226 は脆弱な workflow が PR #10765 で削除されたと報告しています。ここで示す比較演算子の変更をプロジェクトが適用したという意味ではありません。旧チェックは -gt を使い、秒単位で等しい時刻を通していました。説明用の -ge は等しい値を拒否しますが、承認をレビュー済みの正確なコミットに結び付ける方が強固です。未信頼ビルドと OIDC ジョブを分離し、承認された SHA から再ビルドして公開前に来歴を検証してください。exploit payload は含みません。
# 削除済み marimo-bot workflow:秒単位の比較
if [[ $(date -d "$pushed_at" +%s) -gt $(date -d "$COMMENT_AT" +%s) ]]; then
exit 1
fi
# 記録された head_sha を checkout し、その成果物を
# 別の公開ジョブに渡していました。
# 説明用の制御です。GHSL によると脆弱な workflow は
# その場で修正されたのではなく削除されました。
if [[ $(date -d "$pushed_at" +%s) -ge $(date -d "$COMMENT_AT" +%s) ]]; then
exit 1
fi
# より強い設計:レビュー済みの不変 SHA を承認し、
# 信頼されたジョブで再ビルドして検証済み出力を公開します。
エンジニアリング&システム堅牢化チェックリスト
- ✓削除済み marimo bot workflow の影響を受けるコピーを削除または置換し、現在のリポジトリで脆弱な公開経路が有効でないことを確認します。
- ✓メンテナーの承認を正確な不変 Pull Request SHA に結び付け、checkout 前に head が変わったら失敗させます。
- ✓秒単位の時刻だけを、可変ブランチが承認版である唯一の証拠にしません。
- ✓未信頼 Pull Request は公開資格情報なしでビルドし、id-token: write は別の信頼された公開ジョブに限定します。
- ✓未信頼コードが作った成果物を昇格させず、信頼された公開経路で承認済み commit から再ビルドします。
- ✓TestPyPI や npm への公開前に成果物の来歴、ソースリビジョン、パッケージ内容、公開先を検証します。
- ✓GHSL アドバイザリは脆弱な経路の根拠として扱い、実際のパッケージ侵害や悪用の証拠とは扱いません。