Repository navigation
[security][tools] Bash の閉じ込めの検査が、brace の展開から出てくる ~ を確かめず、home の一覧を読める(#628 のレビューで発見) #641
Description
背景
#628 の merge 前レビュー(H-13、2026-10-09)で見つけた、Bash の閉じ込めの検査の既存の見逃しです。#628 の前の develop にもあり、#628 で緩んだものではありません(2026-10-09、利用者承認で起票)。着手前調査(H-14、2026-10-09)で、#628 と #635 の merge 後の develop(b506fbdf)でも同じ値であること、書き込み先の同じ形も漏れていることを確かめ、設計を決めました。どの調査も、判定の関数を tempdir の fixture に対して呼び、結果を見ただけです。shell の挙動は、外の読み書きを伴わない echo と、/dev/null を読む形だけで確かめました。
問題
brace の展開から ~ で始まる語が出てくると、その語は home として確かめられず、home の一覧や中身を読め、home に書けます。shell は brace の展開の後で ~ を展開します(HOME=/HOMEX sh -c 'echo {~/f,y} {~,x}/f' の出力は /HOMEX/f y /HOMEX/f x/f)。リダイレクトの行き先の brace も展開されます(sh -c 'cat < {/dev/null,}' は /dev/null を読んで成功する)。
R:2 段目の閉じ込めの判定、A:書き込みと認識、W:書き込み側の拒否、V:bash:verify の自動許可。
| 入力(例) | develop の値 | 期待 |
|---|---|---|
ls {~,x}、ls {x,~}、ls {~root,x}、cat {~,~}、ls {~/,x}、ls {~+,x}、cat {~/.bashrc,x}、ls {~,x}/f、ls {{~,x},y}、du -sh {~,.}、find {~,.} -name x、grep -r k {~,src} |
R=0・V=1 | R=1 |
tee {~/f,y}、cp a.txt {~/f,y}、touch {~/f,x}、rm {~/f,x}、dd if=in of={~/f,y}、echo x > {~/f,y}、cp a.txt {x,~} |
A=1・W=0 | W=1 |
比較:ls {..,x}、ls {,~}、echo x > {~/f,}、mv a.txt {~/f,} は今も拒否されます(展開の結果の .. か空の語で止まる)。ls x{~,y}(x~ になり ~ は展開されない)と ls {x~,y} は、shell でも home にならないので、許可のままでよい形です。
影響
brace を 1 つ書くだけで、ワークスペースの外(home)の一覧と中身を読め、home のファイルを書き換え・削除できます(rm {~/f,x})。
原因
~で始まる語は、読み取りと書き込みの証明の入口で拒否しますが、その判定は brace を展開する前の語({~,x})にしか当てていません。- brace を展開した後の各語は、ワークスペースからの相対パスとして確かめるだけで、
~という名前の相対パスとして通ります。..と空の語は、相対パスの検査で止まるので漏れません。 - 読み取りの glob・brace の語と、書き込み先は、同じ展開の証明を通るので、両方で漏れています。
設計(決定)
- brace の展開の結果の各語が
~で始まるとき、home の語として拒否する。 展開の証明(brace を展開して各語を確かめる関数)で、展開した直後、glob の一致を探す前に確かめます。読み取りの glob・brace の語と、書き込み先の両方が、この 1 か所で閉じます。 - glob の一致で見つかった名前(ワークスペースの中の
~xという名前のファイル)には当てません。shell は glob の結果の~を展開しないためです。 - 拒否の理由は、既存の「home-relative」の文に合わせます。event の名前や schema は変えません。
- 取らない案:読み取りの判定(read guard)で語を展開して [security][tools] Bash の閉じ込めの検査が、.. と ~ だけの語を確かめず、dd の of= を書き込みとして認識しない(#613 の調査で発見) #628 の親・home の判定を当てる。展開の証明と二重になり、書き込み先は閉じません。
- 試作(展開の証明に 3 行)で、上の表の形がすべて期待どおりになりました。
誤拒否の見積り
- 記録(agent の Bash コマンド、重複なし 436 件):
~を含む brace は 0 件です。試作で 436 件の値は 1 件も変わりませんでした。 - 参考(このリポジトリで動いた Claude Code の Bash コマンド、重複なし約 5.9 万件。正規表現で数えただけ):
~を含む brace に見えたのは 2 件で、どちらも${…}のパラメータ展開でした。brace の展開は 0 件です。 - 新しく拒否される形:
echo {~,x}(表示だけのecho。echo {..,x}が今も拒否されるのと同じ扱い)と、ls {"~",x}(引用した~は shell では展開されないが、字句の読み方が引用を区別しないため。厳しい向き)。 - ワークスペースの中の brace(
ls {src,tests}、cat {a,README}.md、cat {a,b}.txt、ls src/{main,lib}.rs、cp a.txt{,.bak}、mkdir -p x/{a,b}、touch {a,b}.txt、ls {1..3}、ls {a..c}~)は変わりませんでした。
受け入れ条件
- 上の表の形が期待どおり拒否される(読み取りは R=1、書き込み先は W=1)。
- ワークスペースの中の brace の読み書き(
ls {src,tests}、cat {a,b}.txt、touch {a,b}.txt、cp a.txt{,.bak})と、ls x{~,y}を誤って拒否しない。glob の一致で見つかる~で始まる名前のファイルを拒否しない。 - 誤拒否の見積り(記録 0 件、参考 0 件)と、新しく拒否される形を記録する。
- 保護 path、秘密情報、bash:verify の自動許可、[security][tools] Bash の書き込み検査の字句解析がバッククオートのコマンド置換を扱わず、中の書き込みを見逃してワークスペース外へ書き込める(#576 の調査で発見) #581・[security][tools] Bash の字句解析が二重引用の中の $(…)・${…} の " を引用の閉じと読み違え、後ろをコメントとして消してワークスペース外へ書き込める(#581 のレビューで発見) #585・[security][tools] Bash の 2 段目の path 検査が、$・glob・動的な値で静的な相対パスや展開先を確かめず、ワークスペース外を読める(#571 を統合) #582・[security][tools] Bash の書き込み先で、引用した閉じ記号と実行される glob・brace が混ざると、外向き symlink の先への書き込みを拒否しない(#582 のレビューで発見) #602・[security][tools] Bash の 2 段目の path 検査が、空白を含む静的パスと = 付きの引数を候補にせず、外を読める(#582 のレビューで発見) #603・[security][tools] Bash の閉じ込めの検査が、引用していない CR を区切りとして扱い、/ を含まない相対の語を候補にしないため、外向き symlink を通して外を読み書きできる(#602・#603 のレビューで発見) #613・[security][tools] Bash の閉じ込めの検査が、.. と ~ だけの語を確かめず、dd の of= を書き込みとして認識しない(#613 の調査で発見) #628・[security][tools] Bash の cd・pushd の行き先が 1 つに一致する glob だと作業ディレクトリが検査されず、外を読み書きできる(#613 のレビューで発見) #635 の印と判定が緩む向きに変わらない。今の decision の表([security][tools] Bash の 2 段目の path 検査が、$・glob・動的な値で静的な相対パスや展開先を確かめず、ワークスペース外を読める(#571 を統合) #582 の corpus の表と、H-03〜H-14 の probe)で、R・A・W・P・S が 1→0 になる行と、V が 0→1 になる行が 0 件である。
- 既存の検証・受入・証跡・リリースゲートを緩めていない(AGENTS.md の honest-failure 方針)。成長上限の baseline を引き上げていない。
対象ファイル
src/tools/path_guard/bash_pattern.rstests/issue641_bash_brace_home.rs
参照
- 試験は新しいファイルに置きます([security][tools] Bash でオプションにより作業ディレクトリを変える形(tar -C・git -C など)と、- で始まる pushd の行き先が検査されない(#613・#635 のレビューで発見) #637 と同時に進めるため。[security][tools] Bash の 2 段目の path 検査が、$・glob・動的な値で静的な相対パスや展開先を確かめず、ワークスペース外を読める(#571 を統合) #582 の decision の表と、[security][tools] Bash の閉じ込めの検査が、.. と ~ だけの語を確かめず、dd の of= を書き込みとして認識しない(#613 の調査で発見) #628 の試験のファイルは変えない)。
- 着手前調査の記録:ローカルの workspace/tmp/1007/wave1/results/H-14/report.md(試作の差分は SSD の wave1-20261007/h14/proto.diff)
- 発見の記録:ローカルの workspace/tmp/1007/wave1/results/H-13/report.md の「後続の候補 F1」
根拠(develop b506fbdf)
~の拒否は展開の前の語だけ:src/tools/path_guard.rs:208-223(書き込み・展開の証明)・:230-238(読み取りの字どおりの証明)- 展開した各語は相対パスとして確かめるだけ:
src/tools/path_guard/bash_pattern.rs:42-58 - 読み取りの glob・brace の語は展開の証明に回る:
src/tools/bash/read_guard.rs:132、src/tools/bash.rs:1027-1033
関連(参考)
- [security][tools] Bash の閉じ込めの検査が、.. と ~ だけの語を確かめず、dd の of= を書き込みとして認識しない(#613 の調査で発見) #628
- [security][tools] Bash でオプションにより作業ディレクトリを変える形(tar -C・git -C など)と、- で始まる pushd の行き先が検査されない(#613・#635 のレビューで発見) #637
- [security][tools] Bash の書き込み先の glob・brace を展開前の文字列で判定するため、中の symlink を通ってワークスペース外へ書き込める(#509 の調査で発見) #567
- [security][tools] Bash の字句検査では、プログラム経由の間接書き込みや検証コマンドの副作用を閉じ込められない #502
Activity
Merge pull request #644 from Kewton/feature/issue-641-security-tools-…
Kewton commentedon Oct 9, 2026
PR #644 で develop に merge しました(merge commit 88d5a0d、CI・acceptance・Next.js domain oracles success)。glob・brace の展開の結果が ~ で始まる語を、展開の証明の 1 か所で拒否するようにしました(読み取りと書き込み先の両方)。merge 前レビュー(H-15)は blocker 0。