Skip to content

#635 [security][tools] Bash の cd・pushd の行き先が glob・brace のとき、作業ディレクトリを決められないとして検査する - #638

Merged
Kewton merged 2 commits into
developfrom
feature/issue-635-security-tools-bash-cd-pushd-1-glob-613
Oct 9, 2026
Merged

Kewton merged 2 commits into
developfrom
feature/issue-635-security-tools-bash-cd-pushd-1-glob-613

Conversation

@Kewton

@Kewton Kewton commented Oct 9, 2026

Copy link
Copy Markdown
Owner

概要

Bash の閉じ込めの検査で、cd・pushd の行き先が glob・brace の文字(*・?・[・]・{・})を含むと、作業ディレクトリの候補にも「決められない」の印にもならず、その後の相対パスが検査されていませんでした。行き先のディレクトリの中の外向き symlink を通して、外を読み書きできました(例:cd s2* && cat lf4、cd s2* && echo x > lf4)。#613 の merge 前レビュー(H-10)で見つけた、#613 より前からある見逃しです。

この PR は、Issue 本文の設計(案 1)どおり、glob・brace を含む行き先を「作業ディレクトリを決められない」とみなして検査します。

変更(対象 3 ファイル、+344/−8)

  • src/tools/bash_write_guard/working_directory.rs:Inspection に glob_destination の印を足す。cd・pushd の最初の位置引数(-P・-L・-- の後も含む)が glob・brace の文字を含むと印を立て、undecidable にもする。CR の 2 つの読み方の和(merge)では OR。引用・エスケープした字どおりの括弧も同じ扱い(字句の読み方が区別しないため)。
  • src/tools/bash.rs:/ のない語と相対の候補を確かめる分岐の条件に || glob_destination を足しただけ。拒否は既存の path_reference_rejection。
  • 書き込み側は、既存の「working directory change that cannot be determined」の拒否をそのまま使う(W=1)。
  • tests/issue635_bash_glob_cd_destination.rs(新規):本文の表の全部の形(読み取り 24 形と root の絶対パスの glob、書き込み、保護ファイル)、CR の和、候補の上限、cd s2* 単独、値が変わらない形(cd sub && …、cd src && ls *、cat s2*/x、env | grep CDPATH、echo $CDPATH)。[security][tools] Bash の 2 段目の path 検査が、$・glob・動的な値で静的な相対パスや展開先を確かめず、ワークスペース外を読める(#571 を統合) #582 の corpus の表と既存の試験のファイルは変えていない。
  • event の名前と schema は変えていない。

検証

  • commandmate verify の 15 ゲート:develop 2a078deb を取り込んだ HEAD で 15/15 pass(da7292b0、scope 3 本、違反 0)。
  • TMPDIR=/tmp cargo test --test issue635_bash_glob_cd_destination --test issue568_bash_cwd_write_targets --test issue582_bash_read_candidates(CI と同じ条件を作るため):取り込んだ HEAD で exit 0、7 passed・0 failed、28 passed・0 failed、7 passed・0 failed(issue568・issue582・issue635 の順)。
  • 二点測定(develop 2a078deb の src + この PR のテスト):新しい 4 本が FAIL(cd s2* && cat lf4、cd s2* && echo x > lf4、cd s2* && rm tests/spec.rs、cd s2* が拒否されない)。値が変わらないことを確かめる 1 本は develop でも pass。
  • 変異テスト(cargo mutants --jobs 1、--in-diff、--lib と結合テスト 3 本、17 件):1 回目は missed 3。許可が増える向きの 2 件(merge の |=→&=、候補の上限の >→==)はテストを足して直した。2 回目は caught 12・missed 1・unviable 4。残る 1 件は上限の >→>=(ちょうど 64 で上限の印が立つ、厳しくする向き)。
  • merge 前レビュー(H-12):merge 可、blocker 0。判定の関数を fixture で呼んだ 1456 件を base と比べ、R・A・W・P・S が 1→0 の行、V が 0→1 の行は 0 件。変わったのは R 0→1 が 129 件、W 0→1 が 15 件で、どちらも厳しくなる向き。前置き(builtin・command・env・\cd など)、オプション、リダイレクト、複合コマンドの抜け道も拒否されることを確かめた。

意図した誤拒否

  • glob・brace の cd の後のコマンドは、ワークスペースの中に留まる読み書きでも拒否される(cd s2* && ls、cd s2* && cargo test、cd s2* 単独)。行き先を字どおりに書けば通る(cd s2 && …)。
  • 引用やエスケープで字どおりにした括弧の行き先(Next.js の動的ルートのディレクトリ、例:cd "src/app/[id]" && cat page)も拒否される。root からの相対パスで書けば通る(cat "src/app/[id]/page")。記録の 436 件では 0 件、参考の母集団(約 5.9 万件)では 3 件の形。字どおりの括弧を区別して候補に足すのは後続の候補。

Refs #635

🤖 Generated with Claude Code

Kewton and others added 2 commits October 9, 2026 10:59
A `cd`/`pushd` destination holding a glob or brace metacharacter
(`* ? [ ] { }`) added no working-directory candidate and no "cannot
determine" mark, so a following relative path was judged against the
workspace root alone and an outward symlink inside the destination let a
read or write escape (Issue #635, found reviewing #613).

The walk now flags such a destination `glob_destination` and, like the
existing CDPATH/loop/function cases, `undecidable`, so the write side
keeps its existing refusal. The second stage refuses the `/`-less
relative words under the new mark too; the mark is narrower than
`undecidable` and is set only for a glob/brace destination, so a command
with no `cd` (`env | grep CDPATH`, `echo $CDPATH`) keeps its handling.
A quoted or escaped bracket (`cd "s[2]"`) is flagged the same way, since
the lexical read cannot tell it apart from an executed one.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Pin two behaviours that had no failing test (Issue #635 review,
cargo mutants missed 3 / 1):

- `Inspection::merge` must union the glob-destination mark: a unit test
  where only one carriage-return reading saw a glob or brace destination
  asserts the merged mark survives, so a `|=` read as `&=` fails. The
  integration shape `cd \rs2* && cat lf4` fixes R=1.
- The candidate cap must count a growth that passes MAX_CANDIDATES
  without landing on it: forty repeated `cd sub` add one candidate each,
  then `cd r` doubles the set past the bound. A unit test asserts the
  walk is undecidable and an integration test asserts the relative write
  is refused, for the `cd` and `pushd` branch alike, so a `>` read as
  `==` fails.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
@Kewton
Kewton merged commit e5c6a37 into develop Oct 9, 2026
5 checks passed
@Kewton
Kewton deleted the feature/issue-635-security-tools-bash-cd-pushd-1-glob-613 branch October 9, 2026 08:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant