Skip to content

[security][tools] Bash の cd・pushd の行き先が 1 つに一致する glob だと作業ディレクトリが検査されず、外を読み書きできる(#613 のレビューで発見) #635

Closed

Description

@Kewton

背景

#613 の merge 前レビュー(H-10、2026-10-09)で見つけた、Bash の閉じ込めの検査の既存の見逃しです。#613 の前の develop(0ccc81bd)にもあり、#613 で緩んだものではありません。着手前調査(H-11、2026-10-09)で、#613 の merge 後の develop(2a078deb)でも同じ値であることを確かめ、設計を案 1 に決めました。どちらの調査も、判定の関数を tempdir の fixture に対して呼び、結果を見ただけです。shell は起動しておらず、ワークスペースの外の実際の読み書きは試していません。

問題

cd・pushd の行き先が glob・brace の文字(*・?・[・]・{・})を含むと、作業ディレクトリの候補にも「決められない」の印にもならず、その後のコマンドの相対パスが検査されません。行き先のディレクトリの中にある外向き symlink を通して、外を読め、外に書けます。引用やエスケープで字どおりにした括弧(cd "s[2]"、Next.js の動的ルートのようなディレクトリ)も同じ扱いで、検査されません。

R:2 段目の閉じ込めの判定、A:書き込みと認識、W:書き込み側の拒否、P:保護 path の書き込みの検出、V:bash:verify の自動許可。fixture:ワークスペースの中の s2 は普通のディレクトリで、その中の lf4 は外のファイルを指す symlink。s[2] も字どおりの名前のディレクトリで、中に外向きの lf5 があります。

入力(例) develop の値 期待
cd s2* && cat lf4、cd s? && cat lf4、cd s[2] && cat lf4 R=0 R=1
cd {s2,x} && cat lf4、cd {s2,x}; cat lf4、cd s{2,} ; cat lf4 R=0 R=1
cd -P s2* && cat lf4、cd -L s2* && cat lf4、cd -- s2* && cat lf4 R=0・V=1 R=1
cd s2* && cd . && cat lf4、cd sub && cd de* && cat lf3、cd su? && cd deep && cat lf3 R=0 R=1
pushd s2* && cat lf4、pushd {s2,x} && cat lf4 R=0・V=1 R=1
(cd s2* && cat lf4)、{ cd s2*; cat lf4; }、if cd s2*; then cat lf4; fi R=0・V=1 R=1
cd s2* の後に改行・;・|| で cat lf4 R=0 R=1
cd "s[2]" && cat lf5、cd 's[2]' && cat lf5、cd s\[2\] && cat lf5 R=0 R=1
cd s2* && echo x > lf4、cd s2* && tee lf4、cd s2* && cp f lf4、cd s2* && touch lf4 A=1・W=0 W=1
保護ファイルのあるディレクトリへ glob で cd して、その保護ファイルを rm・tee・> で書く A=1・W=0・P=0 W=1

比較:2 つ以上に一致する glob の行き先(cd s* && …)と、$・~・..・- の行き先は、今も拒否されます。heredoc の本文の中の cd(bash <<EOF の中)は shell の中の shell の形(#502)で、この Issue の範囲の外です。

原因

  • 行き先が glob・brace の文字を含むと「決められる行き先」ではないとして、候補に何も足しません。
  • 一方で「決められない」の印も立てないので、相対パスの検査は、ワークスペースの直下を基準にした判定だけで終わります。
  • 行き先の語そのものは、書き込み側では glob を展開して確かめますが、展開した先がワークスペースの中なら通ります。その中の symlink は確かめません。

設計(決定:案 1)

  • 1. glob・brace の文字を含む行き先は、作業ディレクトリを決められないとみなす。 cd・pushd の最初の位置引数(-P・-L・-- の後も含む)が *・?・[・]・{・} のどれかを含むとき、作業ディレクトリの検査を「決められない」にします。2 段の cd、( )・{ }・if の中、改行・;・|| の後も同じです。引用やエスケープで字どおりにした括弧も同じ扱いにします(字句の読み方は、行き先が引用されていたかを区別しないため。区別は「後続の候補」)。
  • 2. 「決められない」のときの検査を、/ のない語にも届かせる。 今の develop は、/ のない相対の語(cat lf5 の lf5)を作業ディレクトリの候補に対して確かめる分岐を、候補が 1 つ以上足されたときにしか通りません。glob・brace の行き先の印を別に持ち、その印があるときも、この分岐で拒否します。印は、glob・brace の行き先だけに立てます(CDPATH の語だけを含む env | grep CDPATH・echo $CDPATH のような、cd のないコマンドを新しく拒否しないため)。
  • 3. 書き込み側は、既存の「決められない」の拒否をそのまま使う。 相対の書き込み先は W=1 になります。保護 path の検出(P)は、glob の行き先を候補に足さないので 0 のままです。書き込みは W で止まります。
  • 4. 印と理由の文。 拒否は既存の path_reference_rejection と、書き込み側の既存の「working directory change that cannot be determined」の理由を使います。event の名前や schema は変えません。
  • 取らない案:案 2(glob を展開して候補に足す)。(a) 作業ディレクトリの検査に、ワークスペースの root を渡す変更が要ります。(b) 同じコマンドの中で先に mkdir したディレクトリ(mkdir s3 && cd s*)は、検査の時点の展開に現れず、実行の時点の一致と食い違います。(c) brace は複数の引数に、2 つ以上の一致は cd の失敗になり、nullglob・failglob・dotglob でも結果が変わります。単純で穴の少ない案 1 を取ります。

誤拒否の見積り

  • 記録(dev-reports と workspace/management の jsonl から取った agent の Bash コマンド、重複なし 436 件。うち cd・pushd を含むもの 186 件):glob・brace を含む cd の行き先は 0 件です。試作で 436 件の値は 1 件も変わりませんでした。
  • 参考(このリポジトリで動いた Claude Code の Bash コマンド、重複なし約 5.9 万件。agent の記録とは別の母集団):cd を含む約 2.2 万件のうち、glob・brace の文字を含む行き先は 54 件でした。大半は $ を含む形(cd ../repo-${n})か、ワークスペースの外の絶対パスの glob(cd /…/CommandAgent-issue-503-*)で、どちらも今も拒否されます。新しく拒否される形は、引用した字どおりの括弧の 3 件(Next.js の動的ルートのディレクトリへ引用して cd する形。例は「## 参照」)です。
  • 新しく拒否される形と、書き直し方:
    • glob の cd の後の、ワークスペースの中に留まる読み書き(cd s2* && cat x、cd s2* && ls、cd s2* && cargo test)。行き先を字どおりに書けば通ります(cd s2 && …)。
    • 引用した字どおりの括弧のディレクトリへ cd する形。root から相対パスで書けば通ります(例は「## 参照」)。
    • cd s2* 単独も拒否されます(行き先の語が「決められない」の後の相対の候補になるため)。
    • heredoc の本文にある cd(cat <<EOF⏎cd s2*⏎EOF⏎cat x)も拒否されることがあります(区切りを引用しない heredoc の本文が、字句の検査に残るため)。

受け入れ条件

対象ファイル

  • src/tools/bash_write_guard/working_directory.rs
  • src/tools/bash.rs
  • tests/issue635_bash_glob_cd_destination.rs

参照

根拠(develop 2a078deb)

  • glob・brace の行き先は候補に足さない:src/tools/bash_write_guard/working_directory.rs:242-247(is_determinable)・:251-254(extend)
  • 「決められない」の印にもならない:src/tools/bash_write_guard/working_directory.rs:225-229
  • cd・pushd の行き先の取り出し:src/tools/bash_write_guard/working_directory.rs:192-217
  • / のない語の分岐は、候補が足されたときだけ通る:src/tools/bash.rs:829-843
  • / のある相対の候補は「決められない」で拒否する:src/tools/bash.rs:805-811
  • 書き込み側の「決められない」の拒否:src/tools/bash_write_guard.rs:198-207

後続の候補(この Issue の範囲の外)

関連(参考)

Activity

  1. added a commit that references this issue on Oct 9, 2026
  2. Kewton commented on Oct 9, 2026

    @Kewton
    OwnerAuthor

    PR #638 で develop に merge しました(merge commit e5c6a37、CI・acceptance・Next.js domain oracles success)。glob・brace の文字を含む cd・pushd の行き先を、作業ディレクトリを決められないとして検査するようにしました。merge 前レビュー(H-12)は blocker 0。レビューで見つかった既存の穴は #637・#502 で扱います。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions