Copy Fail(CVE-2026-31431)は、ローカルの未特権ユーザーがroot権限を奪える脆弱性として公開されたread-only化、capability削減、使えるコマンドの制限、firewallなど、防御を重ねる設計はやはり大事コンテナの脆弱性の話は、どうしても「結局、全部危ないの?」で終わりがちです。
でも、Gabriel Garrido氏の記事はそこをもう一段深く掘っていて、Podmanのrootless containerは何が強くて、何が弱いのかをかなり実感しやすい形で説明していました。個人的には、こういう「理屈だけじゃなくて、実際にどこまで被害が広がるか」を見せる記事はかなり価値が高いと思います。
話の中心は、2026年4月29日に公開された CVE-2026-31431、通称 Copy Fail です。
これはローカルの未特権ユーザー、つまり「普通の権限しかないユーザー」が、共有されたPythonスクリプトを使ってrootシェルを取れてしまう脆弱性です。rootシェルというのは、ざっくり言えば「そのマシンを好きに触れる最強権限」です。これが取れると、ファイルの改ざん、設定の書き換え、他のユーザーの情報へのアクセスなど、やれることが一気に増えます。
しかもこの記事が面白いのは、この脆弱性がLinux containerにも効くという点です。
コンテナは「アプリを隔離して動かす仕組み」として広く使われていますが、現実にはWebサービス、開発環境、CIジョブなど、かなり重要な用途に入っています。だから、コンテナ1個が取られるだけでも油断はできません。
この記事の出発点は、筆者がDockerからPodmanへ移った理由でもあります。
Podmanの魅力は、非特権ユーザーのままコンテナを動かしやすいこと。これを rootless と呼びます。
ここで言うrootlessは、「コンテナの中でrootとして見えても、ホストOS全体のrootではない」という話です。
要するに、コンテナ内のroot ≠ ホストのroot です。これ、すごく大事です。
Podmanは Docker のような「rootful daemon」が前提の構造とは違い、podman run を実行したユーザーの子プロセスとしてコンテナを起動します。
そのため、コンテナ内のプロセスはホスト上で見ても、そのユーザーに紐づいたままです。
記事では、ユーザー bar(UID 1001)でPodmanを使い、PythonのHTTPサーバーを立てる例が示されています。
このとき ps で見ると、python3 プロセスは bar 所有です。Dockerの典型的な構成だと、同じように見えても裏ではrootful daemonが動いていて、コンテナプロセスがroot側から生まれることがあります。ここはPodmanの設計思想の違いがかなり効いています。
正直、この違いはセキュリティ上かなり大きいと思います。
「コンテナを動かすために、結局ホストのrootが必要」という運用だと、コンテナとホストの境界がぼやけやすいからです。Podmanはそこをかなりきれいに切っています。
では、コンテナの中で root に見えるプロセスは何者なのか。
ここで登場するのが user namespace です。
user namespace は、コンテナ内とホスト側でUID/GIDを別々に見せる仕組みです。
UIDは「誰のものか」を表す番号、GIDはグループの番号です。難しく聞こえますが、要は“所有者ラベル”です。
記事の例では、コンテナ内の root(UID 0)は、ホスト上ではユーザー bar(UID 1001)に対応します。
つまりコンテナ内で「私はrootです」と名乗っていても、ホストから見ると「いや、あなたはbarさんですよ」という感じです。
さらに subuid の設定で、bar に割り当てられるUIDの範囲が決まっています。
この記事では bar:165536:65536 のような設定が示されていて、bar の名前空間の中で使える別UIDの領域が与えられています。
ここで個人的に面白いと思ったのが、podman unshare で見ると、ホストでは bar:bar だったホームディレクトリが、namespace の中では root:root に見える点です。
同じディレクトリなのに、見える世界が変わる。まさに“名前空間”という感じで、コンテナの仕組みを直感的に理解しやすい例だと思います。
「rootに見えるなら何でもできるのでは?」と思いたくなりますが、そこはホストのrootとは別です。
コンテナ内のrootができることは、そのnamespaceと権限の範囲内に限られます。
ただし、コンテナの中でもパッケージのインストールやファイル操作の一部は、やはり特権が必要です。
そこで Podman は Linux capabilities を使います。
capabilities は、rootの権限を丸ごと与えるのではなく、
この記事では、イメージのビルド中に apt がいくつかの capabilities を持って動いている様子が示されています。
これがあるから、コンテナ内の root は apt install のような処理を進められるわけです。
ここで面白いのは、--cap-drop=all で全部の capability を落とすと、今度は apt がちゃんと動かずビルドが失敗することです。
つまり、便利さと安全性はトレードオフになりやすい。
「全部落とせば安全」は正しいようでいて、実運用ではそう単純ではないんですよね。必要な権限だけを残す、という設計が重要になります。
ここがこの記事の核心です。
結論から言うと、効きます。少なくとも筆者のテストでは、Copy Fail を使って rootless container の中で root shell を得ることはできた とされています。
ここだけ聞くとかなり怖いです。
「rootlessなのに結局root取られるの?」と思いますよね。私も最初そう思いました。
でも大事なのは、その“root”がどこまでのrootかです。
Podmanのrootless containerでは、コンテナ内のrootを取られても、ホスト上の権限までそのまま飛ぶわけではないのです。
記事では、被害の広がりはかなり限定されるとされています。
つまり、Copy Failで得られるのは“コンテナ内の支配権”であって、“ホスト全体の王座”ではない、ということです。
この差はすごく大きいです。
セキュリティの世界では、侵害をゼロにするのはほぼ不可能なので、どこまで被害を抑えられるかが本質になります。Podmanのrootless設計は、その意味でかなり強いです。
とはいえ、コンテナ内rootを取られて「はい終わりではない」けれど、「たいしたことない」でもありません。
記事でも述べられているように、コンテナが侵害されると、そこを踏み台にしていろいろ悪さができます。
たとえば、以下のようなことが考えられます。
要するに、ホストを直接奪えなくても、アプリやデータの安全は普通に壊せるわけです。
だから「rootlessだから安心」と言い切るのは危険だと思います。
むしろ正しくは、「ホストまで巻き込む最悪ケースを減らせるが、コンテナ侵害そのものは重大」という理解が近いはずです。
記事の後半では、defence in depth、つまり「防御を何重にも重ねる」考え方が紹介されます。
これ、セキュリティの基本ですが、実際にはかなり大事です。1枚の防壁に期待しすぎると、破られた瞬間に全部終わります。
紹介されている対策の方向性は、たとえば次のようなものです。
コンテナのイメージを読み取り専用に近い形で扱うことで、改ざんしにくくする。
侵入されても、書き換えられる範囲を減らせます。
CPUやメモリ、プロセス数などの制限をかける。
暴走やDoSっぽい挙動を抑えやすくなります。
コンテナ内に置くコマンドを必要最小限にする。
攻撃者に便利な道具を与えない、という発想です。これは地味ですが、かなり効くことがあります。
通信先を絞る。
侵入後の外部通信や横展開を難しくできます。
個人的には、こういう対策は「地味だけど正義」だと思います。
脆弱性対策というとパッチ適用ばかりに目が行きますが、実際には侵入されても被害を小さくする設計がめちゃくちゃ重要です。
この文章を読んで一番印象に残るのは、Podman rootless が「無敵」だから優れているのではなく、壊れ方がマシだから優れている、という点です。
Copy Fail のような脆弱性があっても、rootless container ならホスト全体のroot奪取に直結しにくい。
これはかなり大きな差です。
ただし、そこで安心しきるのは違います。
コンテナ内rootの取得は、依然としてアプリやデータにとって重大な事故です。
だからこそ、Podmanのrootless設計をベースにしつつ、capabilityの削減、read-only化、ネットワーク制限などを組み合わせるのが現実的な守り方だと思います。
要するにこの話は、
「rootlessだから安全」ではなく、「rootlessだから被害を限定できる。だからさらに守りを重ねる」
という理解に落ち着くのではないでしょうか。
こういう記事は、コンテナを「便利な箱」としてだけ見ている人に、かなり良い刺激になるはずです。
便利な技術ほど、内部の仕組みを少し知っているだけで、運用の勘所がぐっと変わります。Podmanのrootless containerは、その好例だと思いました。