Blackbox Blast
BB Preflight
← 事故ログへ

CASE · 軽微 · other

未検証の報告公開情報からの収集

エージェントを専用ユーザーに閉じ込めたのに、root の構成スクリプトが抜け道になっていた(未検証の報告)

筆者によれば、sudo を持たない専用ユーザーで AI コーディングエージェントを動かす自作ツールで、そのユーザーのホームを root が書く構成・更新スクリプトに穴があった。ホーム内の設定ファイルを、ホームの外の保護対象ファイルを指すシンボリックリンクに置き換えると、次の更新で root がリンク先を書き換え、所有者まで専用ユーザーに変えた。筆者自身による報告で、実際の被害には触れていない。

約6分で読めます

発生日
分類
other
影響範囲
none
検知
ai-code-review
タグ
#symlink #root-script #dedicated-user #privilege-boundary #claude-code #codex #regression-test #linux

CH 1

原因

筆者によれば、ユーザーのホームの中のファイルは見た目どおりとは限らないのに、root の権限のまま書いていた。リンクは末端のファイルだけでなく、パスの途中のディレクトリに置かれても同じ結果になった。直前の版の write_agent_file は、途中のディレクトリの作成こそユーザーの権限で行っていたが、最後の install が root で動いていた。

CH 2

結果

筆者によれば、使い捨てのコンテナでの再現では、root だけが読み書きできる検証用ファイルに行が足され、所有者が root から agent に変わった。修正後にも同種の穴が2つ見つかった。1つはプロキシ設定がないときに古い設定を消す root の rm -f、もう1つは root の tar -c によるバックアップで、利用者に読めない root のファイルが書庫に入った。いずれも筆者がコンテナで再現した。

CH 3

対策

筆者は、ホームの中の操作を runuser でそのユーザーの権限に移した。ファイルを開く操作、権限変更、削除も含む。あわせて、末端と途中にリンクを置く回帰試験を使い捨てのコンテナに足し、ホームへの書き込みを関数に集めて、決まりとしてリポジトリの CLAUDE.md に書いた。筆者によれば、2026年10月26日に v0.3.1 で全49件の試験が成功した。

何が起きたか

筆者(PROPAGANDIST CORPORATION)は、AI コーディングエージェントを sudo のない専用ユーザーで動かす自作の構成ツール(propagandist/agent-host-autoinstall)に、抜け道があったと報告している。 そのユーザーの設定を整える root のスクリプトが、ホームの中のシンボリックリンクをたどって、ホームの外の保護対象ファイルを書き換えられる状態だった。 筆者自身の報告で、実際の被害には触れていない。穴が見つかったのは v0.2.0 を出す前で、直した版は v0.3.1 の時点で試験に通っている。

現場の混乱

筆者によれば、見つけたのはリポジトリ全体を AI エージェントにレビューさせたときだった。 Codex が、更新時に root が agent のホームの設定を読み書きし、所有者を変えていると指摘し、使い捨ての Ubuntu 26.04 のコンテナでの再現を添えて起票した。 Claude Code がそれを独立に検証して再現し、起票の本文になかった write_agent_file の経路も見つけた(Issue #1)。

筆者の説明では、流れは次のとおりである。 専用ユーザーは自分のホームの中の設定ファイル(例:~/.config/mimeapps.list)を、保護対象ファイルを指すリンクに置き換えられる。 自分で開いても書けないので、それだけでは何も起きない。 ところが更新のたびに root のスクリプトが同じ設定ファイルを書き、リンクをたどってリンク先を書き換え、最後の chown で所有者を agent に変える。 コンテナでの再現では、root だけが読み書きできる検証用ファイルに行が足され、所有者が root から agent に変わった。 筆者は、エージェントに悪意がなくても、読ませたリポジトリや Web ページの指示、依存パッケージのスクリプト、誤操作などでリンクが置かれうるとしている。

原因

筆者によれば、問題が成立する条件は次の3つがそろったときである。 専用ユーザーが、対象の設定ファイルまたは途中のディレクトリをリンクに置き換えられること。 管理者や自動処理が構成・更新スクリプトを root で実行すること。 そのスクリプトが、ユーザーの管理するパスを root の権限のまま操作すること。

筆者が挙げた具体例は2つある。 1つは、既定のブラウザ設定を書く ini_set が、Python の open(path, "w") で root のまま書いていたことである。 もう1つは write_agent_file で、途中のディレクトリの作成はユーザーの権限で行っていたが、最後の install が root で動いていた。 そのため、途中のディレクトリがシステムの設定ディレクトリへのリンクだと、リンク先に agent の持ち物のファイルが作られた。 筆者は、O_NOFOLLOW で拒めるのは末端のリンクだけで、途中のリンクをシェルのコマンドから一律に拒むことはできないと説明している。 また、Ubuntu の既定の fs.protected_symlinks も、ホームの中のリンクを root がたどるのは止めなかったとしている(筆者が確認)。

対策

筆者は、リンクを先に調べる案ではなく、ホームの中の操作をそのユーザーの権限で行う方法を選んだ。 調べてから書くまでの間にリンクへ置き換えられる恐れ(TOCTOU)があり、途中のディレクトリもすべて調べる必要があるためである。 具体的には、runuser でユーザーの権限でコマンドを動かす agent_run を足した。 write_agent_file は、途中のディレクトリの作成から、同じディレクトリの一時ファイルへの書き込みと mv -T での置き換えまで、すべてユーザーの権限で行う形にした。 既定のブラウザ設定は ini_set --as-agent にして chown をやめた。.bashrc への追記、エディターの設定、~/.ssh の chmod、古い設定の削除も agent_run に移した。

回帰試験は、使い捨てのコンテナの中で root のときだけ動く。 ホームの外に root の持ち物のファイルとディレクトリを置き、agent の権限で末端と途中にリンクを作ってから、実際の関数を呼んで、外側の中身・所有者・権限が変わらないことを確かめる。 筆者によれば、2026年10月26日に v0.3.1 を Ubuntu 26.04.1 の使い捨てコンテナで試験し、全49件の成功を確認した。

筆者は、直したあとに別のエージェントに本文と題材の事実を照らし合わせてもらい、同種の穴を2つ見つけた。 1つは Issue #24 で、プロキシ設定がないときに古い設定を消す root の rm -f である。パスを変数で受けていたため、grep の点検に当たらなかった。 もう1つは Issue #23 で、root の tar -c によるバックアップが、途中のディレクトリのリンクをたどって、利用者に読めない root のファイルを書庫に入れていた。 どちらも v0.3.0 で、ユーザーの権限で扱う形に直した。 筆者は、grep は候補を出すだけで判断は人がするしかないこと、更新の途中でリンクを差し替えられる場合や更新スクリプト全体の網羅は確かめていないことも述べている。

運用者への教訓として、閉じ込めたユーザーのホームを root で書くスクリプトは、そのユーザーの権限で書く形に直し、末端と途中のリンクの回帰試験を置くことが挙げられる。

出典

PREFLIGHTあなたの Mac の備えは、大丈夫?BB Preflight は、AIエージェントの権限や鍵の置き場所など21項目を、読み取りだけで点検する無料の Mac 用ツールです。点検してみる →