Skip to content

[security][tools] Bash の閉じ込めの検査が、brace の展開から出てくる ~ を確かめず、home の一覧を読める(#628 のレビューで発見) #641

Closed

Description

@Kewton

背景

#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}~)は変わりませんでした。

受け入れ条件

対象ファイル

  • src/tools/path_guard/bash_pattern.rs
  • tests/issue641_bash_brace_home.rs

参照

根拠(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

関連(参考)

Activity

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

    @Kewton
    OwnerAuthor

    PR #644 で develop に merge しました(merge commit 88d5a0d、CI・acceptance・Next.js domain oracles success)。glob・brace の展開の結果が ~ で始まる語を、展開の証明の 1 か所で拒否するようにしました(読み取りと書き込み先の両方)。merge 前レビュー(H-15)は blocker 0。

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