
2026/05/09 6:23
非決定性が、CVE のパッチ適用における問題点です。
RSS: https://news.ycombinator.com/rss
要約▶
概要:
サイバーセキュリティにおける最も重要な変化は、人工知能(AI)が既知の脆弱性の体積を急速に増加させ、従来の事後保安スキャンを持続不可能なものにすることです。現在の業界標準では、パッケージの選定を記録する conventional lockfile に依存していますが、これは変更可能なホスト状態への依存により完全に決定論的な環境を保証できず、結局のところ単一の真実源を持たない冗長なアーティファクトを横断して費用のかかる線形スキャンにセキュリティチームを追い詰めます。
対照的に、Flox や Nix などのツールはビルド時に不変(immutable)な環境を強制することで優れした解決策を提供します。これらのシステムは誤りがちである事後分析への依存を避け、依存関係を唯一無二の「クロージャ」——変化しない完全で自己完結型のソフトウェアパッケージ——に解決します。このアプローチにより、同一の依存関係セットが単一のユニットとして扱い効率的な三階(triage)を行えることを明確にするレコードシステムが構築されます。
AI 生成エラーが増大するにつれ、組織はビルド時間の最適化よりも是正速度を最優先する必要があります。不変な依存関係管理を採用することで、チームは単一のマニフェストを更新し、同時にすべての環境に安全な新しいバージョンを促進できます。これにより重複排除された是正が可能となり、冗長なセキュリティ作業を大幅に削減するとともに、時間のかかるスキャンなしで特定のパッケージの脆弱性に関する即時の回答を得ることを可能にします。
本文
クラウド・マイトス(Claude Mythos)が正式発表される以前から、次なる CVE の潮流を AI モデルによって発見する兆候は明確でした。ビッグ・スリープ(Big Sleep)は SQLite にゼロデイ脆弱性を発見し、マイクロソフトのコパイロットはブートローダー関連で 20 件以上の CVE を見つけ出しました。また DARPA は AI による CVE 発見を促進するために AIxCC というイニシアチブを開始しています。
今や、クラウド・マイトスのようなモデルが登場する中での結論は二つです。第一に、AI モデルの性能向上に伴い、CVE 発生速度が急激に加速していくでしょう。第二に、何十年も調査機関によって回避され続けてきたような、バージョン変更を乗り越えてもなお存在し続ける CVE を多数検出できるようになるでしょう。
最も処理が困難なカテゴリの一つが「パッケージ関連の CVE」です。多くの組織には、自らのスタック内にあるすべてのパッケージについて最新の日付を持つマニフェストを持っていません。システムレベルのパッケージマネージャ(dnf、apt、zypper など)やツールチェーン用のパッケージマネージャ(pip、npm、cargo など)は、プラットフォーム、環境、時間を跨いでパッケージバージョンが異なることを解決します。脆弱な依存関係を実際に利用されていないと確信するためには、組織全体に対して手動でスキャンを行わなければなりません。この上、CVE の数が増加し続ける中で、この問題は急速に管理不可能なものになります。
この CVE の急増は、開発者がインストールされたパッケージのための「事実の記録(system of record)」を採用するよう促すべきです。そこで私たちはフロックス(Flox)を構築しました。フロックスとは、開発から本番環境までプラットフォームおよび DevEx チームが中央で環境を管理するためのオープンソース・システムです。フロックスは Nix という宣言型のパッケージマネージャによって実現されており、この Nix は暗号学的に検証可能な依存関係グラフを提供します。Nix と Flox の組み合わせはパラダイムを変革します。つまり、事後的なスキャンを通じて脆弱なパッケージを発見する従来のアプローチではなく、ビルド時においてすべての依存関係を検証可能にし、フロックスの事実の記録システムによって追跡できるようになります。
従来のパッケージマネージャでは、CVE の選別(triage)は実行するアーティファクト、イメージ、ホスト、またはランタイム環境の数に比例して増大します。n 個のデプロイメントがある場合、一般には各々を分析する必要があります。なぜなら、2 つの環境に全く同一の依存関係を有することを証明する信頼性の高い方法がないからです。ビッグ・O ノテーションで言えば、これは O(n) の作業であり、その多くが冗長です。
Nix は分析の対象を変えます。すべての Nix または Flox 環境は、それを作成するために使用された完全な推移的(transitive)パッケージとビルド入力のセットに解決されます。Nix の用語ではこれを「クロージャ(closure)」と呼びます。クロージャは入力によってアドレス指定されているため、2 つの環境が同じ Nix ストア・パスに解決する場合、CVE 選別の単位として同一のものとみなせます。依存関係の集合が一致することを証明するために両者を個別に検査する必要はありません。
これにより、選別問題は重複排除(deduplication)の問題に変換されます。n 個の環境が単一の依存関係集合を共有する場合、高コストな作業(影響を受けるパッケージを確認する、パッチを検証するなど)は、環境ごとに 1 回ではなく、依存関係集合ごとに行われることになります。例えば、500 つの環境が 50 つの固有の依存関係集合に縮約される場合、選別作業は「500 のものをスキャンする」のではなく、以下のプロセスに似ています:
- 各環境をその依存関係集合にマッピングする。
- 依存関係集合が同じ環境をグループ化する。
- 各固有の依存関係集合のみを 1 回分析する。
- その結果をそのグループ内のすべての環境で再利用する。
ビッグ・O ノテーションにおいて、高コストな分析は 500 の環境にわたる O(n) から、50 つの固有の依存関係集合にわたる O(u) にシフトします。
さらに、Nix と Flox を用いることで、最も作業負荷の高いパッケージ CVE クエスチョンの 2 つについて、事実の記録(lockfile)と解決された環境内にすでに要求される証拠が収められています。脆弱な環境を同定するためには、どのロックファイル、クロージャ、または SBOM が影響を受けるパッケージを含むかをクエリし、それらの記録を用いる環境に逆マッピングします。是正を検証するためには、置換グラフと比較し、脆弱なパッケージがもはや存在しないことを確認します。
現状に対して比較すると、Nix/Flox ワークフローはデータ量とエントロピーの観点から低く効率的です。解決された記録をインデックス化し、影響を受けるグラフをクエリし、それらを環境に逆マッピングし、環境定義を変更してパッチ済みのパッケージバージョンを選択し、置換される環境参照(GitHub コミットまたは FloxHub ジェネレーション)をプッシュし、最終的に脆弱な一方との置換グラフを比較します。
これは確かに O(1) ではありませんが、正直に言えば、ビッグ・O の比較はリンゴとオレンジのものです。現状は時間とリソースを要する検査ワークフローですが、Nix/Flox モデルはパッケージ CVE 選別をデータベースへの検索、グラフ比較、および新しい環境参照の原子プッシュという処理へと還元します。
ノンディターミニズム(非決定性)と CVE
ノンディターミニズム(非決定的動作)の原因にはいくつか一般的な要因があります。一部のパッケージマネージャ(例えば apt や dnf)の場合、同一のインストールコマンドでも、実行された環境やミラーからの取得元、キャッシュの有無、およびそのタイミングに基づいて異なる結果が生じる可能性があります。ほとんどのパッケージマネージャはバージョン範囲を許可しており、それにより具体的なパッケージと依存関係が異なって解決される場合があります。その結果として、スタック全体にわたる依存関係グラフのクエリ可能記録が存在しなくなります。
ロックファイルについて
従来のロックファイルは有用であり、パッケージエコシステム内の解決器(resolver)ドリフトを削減または排除するからです。Cargo.lock、package-lock.json、または uv.lock は、そのエコシステムのパッケージマネージャが選択した内容を記録できます。しかしながら、ロックファイルは実行環境の完全な宣言的かつ決定的記述ではありません。すなわち、アプリケーション、サービス、またはワークロードが動作する環境を構成するベースイメージ、ネイティブライブラリ、ツール、証明書、環境変数、および推移的依存関係を含むものではありません。
パッケージ CVE が公開されると、組織は一般的にサービス、イメージ、ホスト、およびランタイム環境全体にわたって検索を行い、露出レベルを決定する必要があります。脆弱なパッケージは誰かが意図的にインストールしたものではありませんことが多いです。実際には、別のパッケージ、ベースイメージ、システムライブラリ、またはランタイム固有のインストールステップによって導入された推移的依存関係であることが一般的です。これが私たちが目撃してきた推移的依存関係サプライチェーン攻撃クラスの背後にある基本的な論理です。
従来のワークフローでは、これは O(n) の作業です:組織は共有された解決済み依存関係グラフがないため、各アーティファクトを独立してスキャンまたは分析しなければなりません。Nix と Flox を用いると、チームは各環境をその解決済み依存関係集合(クロージャ)にマッピングし、同一のクロージャを持つ環境をグループ化できます。依然として O(n) のインベントリ手順が含まれますが、高コストな作業は一意のクロージャ数 u にわたる O(u) にシフトします。
このワークフローでは、CVE が発生した場合の露出判定は、「影響を受けるパッケージ → 影響を受けるクロージャ」というデータベースクエリから始まり、そこからそれらに参照する環境へと続く高速な操作となります。
CVE 選別の重複排除(Deduplication)
ソフトウェアが再現可能な依存関係集合からビルドされると、CVE 選別はもはや各アーティファクトを独立してスキャンすることから始まる必要はありません。代わりに、それぞれのランタイムを構築された解決済み依存関係集合(クロージャ、パッケージメタデータ、SBOM、または同等の依存関係記録)にマッピングできます。適切に維持された依存関係インデックスを持つ場合、露出クエリは CVE 影響を受けるパッケージから影響を受ける依存関係集合へ、そしてそれらの集合から参照する環境へと高速なルックアップとして実行できます。
Nix はどのように決定的(deterministic)を実現しているか?
Nix はソフトウェアをビルド、パッケージ化し消費するための従来のモデルを覆すことで決定性を実現します。多くのパッケージマネージャは、プリビルドされたアーティファクトをグローバルで書き換可能なシステムコンテキストにインストールするため、最終的な環境(アーティファクトが動作するコンテキスト)は(a) アップストリームリポジトリおよびミラーの状態、(b) ホスト自体の状態、および (c) すべての周囲入力によって決定されます。
Nix は正反対のアプローチを採用します:宣言された入力の元からパッケージをビルドし、それらを不変のストア・パスに永続化します。キャッシュからプリビルドされたバイナリ置換を使用する場合でも、それはハッシュ付きの Nix ストア・パスに対応します。これがキーポイントです:Nix はダウンロードされたバイナリを恣意的なパッケージとして扱わないで、既知のビルドレシピと宣言された入力の出力としてのものとして扱います。
このモデルは依存関係グラフをクエリ可能にします。Nix のビルド出力は不変のストア・パスに住み着き、各出力はその完全な推移的依存関係グラフ(パッケージとその依存関係、およびそれらの依存関係)を埋め込みます。(これも「クロージャ」です)。得られた環境は検査され、重複排除され、CVE 選別の単位として再利用できます。分析の単位は「このホストまたはイメージに何インストールされたか?」から、「どの解決済み依存関係グラフが脆弱なパッケージを含むか?」へとシフトします。
Nix のビルドは完封型(hermetic)であり、ホストの周囲状態から隔離されています。同じ宣言された入力が与えられれば、Nix は常に同様の推論とストア・パスを確実に計算します。Nix の出力も検証可能です。Nix ストア内の各パッケージは、その入力を基にした暗号学的ハッシュによって識別されます。
Nix と Flox の実際の違いについてご質問があるかもしれません
Nix は、再現可能な環境を実現するためのパッケージモデル、ビルドシステム、およびストアのセマンティクスを提供します。Flox は、それらの primitives をチーム向けの完全なソフトウェアライフサイクルワークフローに変換することによって Nix に基づいています:環境の作成、パッケージのインストールと更新、複数マシーンでの環境のアクティブ化などです。Flox CLI は install、list、uninstall、activate などの familiar パッケージマネージャコマンドを公開しており、Nix 表現または flake を記述せずに Nix で作業できるようになります。Flox はさらにパッケージの厳選されたカタログ、宣言的な環境マニフェスト、ならびに FloxHub による中央集権的でバージョン管理された共有を追加します。
マニフェストから解決済み依存関係グラフへ
Flox マニフェストはインストールスクリプトではありません:それは、Flox がランタイム時に実装するパッケージ、変数、フック、およびサービスの宣言的記述です。Flox がそのマニフェストを解決すると、結果は manifest.lock という名前のファイルに書き込まれます。このロックファイルを CVE 選別の基盤と考えると良いでしょう:それは FLOX リゾルバーが選択したパッケージバージョン、ソースリビジョン、推論(derivations)、ターゲットシステム、および Nix ストア出力を記録します。これらのストア出力は環境の推移的依存関係グラフを追跡するための出発点です:解決されたパッケージ、そのランタイム依存関係、そしてそれらの依存関係の依存関係。このグラフは検査され、インデックス化され、CVE 露出のためにスキャンされるか、または SBOM の作成に使用されます。
監査および CVE ワークフローのために、これはインストールスクリプトや事後のスキャン結果よりもはるかに強力なものを与えます。インベントリ手順は依然として O(n) です:各環境は実際に使用中の解決済み依存関係記録(manifest.lock、FloxHub ジェネレーション、クロージャフィンガープリント、または SBOM など)にマッピングされる必要があります。しかしその手順は主に事務作業です。高コストな作業は、それらの記録を裏付ける依存関係グラフの解決であり、Nix と Flox はこれをデフォルトで実行します。
残りの CVE 固有の作業は、(1) 既知の脆弱性情報に対してそれらのグラフをインデックス化し、(2) 同等の環境を重複排除し、(3) 特定の CVE が実際に適用されるかを確認することです。環境が同一のロックファイルまたはクロージャでグループ化された後、作業は各環境にわたる O(n) から、一意の解決済み依存関係グラフ数 u にわたる O(u) にシフトします。500 の環境が 50 つの一意のロックファイルまたはクロージャに縮約する場合、高コストな分析は 500 回ではなく 50 回実行されます。
是正も重複排除される
同様のモデルは是正にも適用されます。FloxHub は個別のパッケージと完全な環境に対して SBOM を生成するため、組織は各環境ジェネレーションの解決済み依存関係グラフを持っています。それらを脆弱性情報に対してインデックス化した場合、脆弱性露下の決定はデータベースをクエリすることになります:どの解決済みグラフが CVE 影響を受けるパッケージを含み、そしてどの環境または FloxHub ジェネレーションがそれらに参照するか。注:これは原理的に FloxHub に限定されたものではありません。Nix ユーザーはその下位作業を手動で行うことができます:ストア出力を given として、クロージャをトレースし、それが含むパッケージとライブラリを検査し、そのグラフから SBOM を生成します。
そこからは、チームは関連するパッケージまたは入力を更新し、ロックファイルを再生成し、(Flox と FloxHub を使用している場合)新しい環境ジェネレーションを公開します。是正の質問は非常に具体的になります:新しいロックファイルが脆弱なパッケージの更新バージョンに解決され、そして生じる依存関係グラフはもはや脆弱なパッケージ出力を含んでいないか?
はい、これは O(1) の是正ではありません。チームは依然としてランタイム環境の動作をテストし、展開を調整し、置換される FloxHub ジェネレーションをプッシュする必要があります。しかしこのモデルでは、影響を受けるグラフを 1 回同定し、置換グラフを 1 回検証し、脆弱なグラフが使用されているどこにでもその置換をプッシュします。この再利用は Flox/Nix 環境によってキャプチャされた依存関係に適用されます。アクティベートまたはランタイム時に impérativement 取得されたパッケージまたはアーティファクトは別個に固定され追跡する必要があります。
Flox と Nix が再現可能な出力を保証するため、CVE を修正するのは manifest.lock で依存関係を特定し、manifest.toml を調整して再ロックし、ビルドを再実行し、最後に影響を受けた環境へ展開することと同じくらい簡単です。ビルドが完全に決定的であるため:ローカルで動作すれば、本番環境でも動作します。
なぜこれが標準ではなかったのか?
Nix は dnf、apt、brew などの人気プロジェクトとは非常に異なるパッケージマネージャです。主な理由は価値観の違いにあります。多くのパッケージマネージャは利便性と高速なビルド時間を重視します。Nix は完封型(hermeticism)を重視しており、これはかなり高価です。すべては孤立してビルドされるため、キャッシュされたコピーであっても、より長いビルド時間とより多くのディスクスペースを意味します。
今日、私たちは異なる時代を生きています。ディスクスペースはそれほど希少ではなく、十分なインターネット帯域幅があります。AI システムのニーズと比較すると、Nix のリソース要件は極めて控えめです。振り子効率的なビルド時間の優先から効率的な是正時間の優先へとシフトするかもしれません、特に AI エージェントが CVE 数量を増大させるにつれて。
我々は多くの開発者がパッケージマネージャのリファクタを恐れていることに無知ではありません。 thankfully、コーディングエージェントのおかげで、将来の移行がそれほど恐ろしいものではないと信じていますが、まだそのための最適な経路を探究しています。
コーディングエージェント:(ある程度)良い面と(非常に)悪い面
O(n) と O(u) の比較はコーディングエージェントの世界では自明に思えるかもしれません。Claude Code が数百のファイルにわたって grep を実行してボタンの border-radius を変更している時代です。
インフラストラクチャレベルでは、これは少し異なります。はい、組織は定期的にコードベースを検査し、依存関係を収集して新規の CVE と比較するエージェントを構築できます。モデルが賢くなるにつれて、コーディングエージェントの混沌の中で O(n) スキャン問題は消失するかもしれません。しかし、これは問題に対する短期的な思考法です。AI エージェントが自律的なスキャンを行うためには、各ノードにアクセスし、エラーなく動作し、各 CVE に対して数百回の検索を実行する必要があります。エラーなく定期的に実行できるかもしれませんが、それは良いセキュリティの代わりに「十分だ」という言い訳です。一方、Flox ではエージェントが容易に処理できる単一の真実源があります。
コーディングエージェントも独自の反証をもたらします。今日の超強力なエージェントは善人のみに限定されていません。攻撃者はすぐに CVE をコーディングエージェントに供給し、ガードレールを回避する巧妙なプロンプティングで、スケーラブルな攻撃エンジニアリングを行うことができます。CVE のゼロデイ性は本当にゼロデイ化しています。情報の密度のある時代において、動機付けの高いアクターは組織の公開ディスロージャーに対して攻撃を鋭く磨くことができます。例えば、スタック内の下位パッケージを明らかにしたカンファレンス発表のようなものです。
これは悪性のフライホイールです:AI エージェントはコードベースを手動でスキャンしパッチをプッシュするエージェントと同じ速度で欠陥を見つけ、エクスプロイトをスケールできます。
閉じる thought:新たな時代
この記事が Nix の宇宙に数年間貢献した理由に対する洞察を提供することを願っています。次なる CVE の tidal wave に先立って、決定的なパッケージ管理と事実の記録システムを説得力のある議論として提示することが私たちの願いです。非停止自動化の時代において、良いセキュリティはかつてないほど重要になる我们相信しています。
過去 1 년間にソフトウェア開発領域で以前よりも多くの変化がありました。当社のパッケージ管理アプローチもその一つであるべきです。