Start Debugging

Claude Code 2.1.251、権限チェックを迂回する4つの経路を塞ぐ

チェック後に差し替えられたシンボリックリンク、シンボリックリンク経由の検索パスで効かなくなる deny ルール、プラグインの外を指せるマーケットプレイスのコマンド、承認前に読まれるワークフロースクリプト。1つのリリースに入った4つの修正は、すべて同じバグだ。

Claude Code 2.1.251 は 2026年8月28日にリリースされた。changelog は長く、面白い部分が埋もれている。そのうち4つの修正は同じ形をしている。権限チェックが承認していないファイルに、何かが到達していた、というものだ。まとめて読むと、4つのバグではなく1つのクラスに見えてくる。

チェックは通った。その後にパスが変わった

目玉の修正は、教科書どおりの time-of-check-to-time-of-use 競合だ。changelog によれば、ファイルツールは「権限チェックのあとに作業ディレクトリ内で差し替えられたシンボリックリンクをたどり」、「承認された場所の外を読み書きし得た」。src/config.ts の編集を承認し、パスが解決され、チェックが通る——その「通った」と実際の書き込みの間に、そのエントリが別の場所を指すシンボリックリンクに変わる。

腹に落としておくべきなのは、誰がその差し替えを実行できるかだ。postinstall スクリプト、ファイルウォッチャー、開発サーバー、テストランナー、あるいはエージェント自身が直前に走らせた Bash コマンドが、セッションの開いている間ずっと動いている。作業ディレクトリは静かな場所ではないし、信頼できる場所だったこともない。

Grep と Glob には同じ穴の読み取り側があった。Read(...) の deny ルールが、シンボリックリンクを含む検索パス経由で到達したファイルに適用されていなかった。secrets/** への deny ルールは直接読むときには効き、同じファイルがそこを指すシンボリックリンク経由で一致したときには黙って効かなくなっていた。

あなたではなく設定から来た2つのパス

残る2つは、リポジトリと一緒に運ばれてくるファイル経由で入ってきた。マーケットプレイスのエントリで宣言されたプラグインコマンドは、プラグインディレクトリの外を指すことができた。そうしたパスは、明示的なパストラバーサルエラーで拒否されるようになった。そして Workflow ツールは、権限チェックが走るに、セッションに読む権限のない scriptPath を読んでいた。しかもその内容をエラーメッセージに引用していたため、ブロックされたはずの読み取りが成功した読み取りに変わっていた。

同じリリースで設定も締められている

2.1.251 の他の半ダースほどの変更も同じ方向を向いており、いずれもクローンされたリポジトリを信頼できない入力として扱っている。

どれ一つとして単体では派手なエクスプロイトではない。だが合わせると、「権限システムがノーと言った」と「そのファイルは読まれないままだった」の間の距離を埋めることになる。

アップグレード

claude update、または npm から入れ直す。同じ週の注記が2つある。2.1.250 は同日リリースでバグ修正のみ。2.1.248(8月27日)は --restricted(同義の CLAUDE_CODE_RESTRICTED=1)を追加した。コマンドやコードを実行するツールを取り除き、--tools で明示しない限り WebFetch を落とし、ファイルツールを作業ディレクトリ内に留め、bypassPermissions を拒否し、ユーザー・プロジェクト・ローカルの設定ファイルを完全に無視する。このフラグと今週の修正は、同じ主張を両側から述べたものだ。リポジトリが渡してくる設定とパスは入力であって、設定ではない。

とりわけマーケットプレイスの修正は、2.1.238 がカタログに本物の到達力を与え、プラグインマーケットプレイスが自前の認証ヘッダーを発行できるようにしたちょうど1週間後に来ている。マーケットプレイスのエントリにできることが増えるほど、その周囲のディレクトリ境界が保たなければならないものも増える。

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< 戻る