結論:更新、deny、差し替えtestを一組にする
Claude Codeのsymlink対策は、修正を含むversionへ更新し、workspace外targetへのRead・Write・Editと、symlink経由のGrep・Globをdenyし、許可判定後にlink先が差し替わるケースまで回帰testします。最新の公式releaseでは、permission check後にworkspace内symlinkが交換されるとfile toolが承認範囲外を読み書きできた問題と、symlinked search pathでGrep・GlobがRead deny rulesを適用しなかった問題の修正が明記されています。
読者の具体的な困りごとは、repository内だけを許可したつもりでも、linkの解決先や差し替えtimingにより秘密fileや別projectへ触れる可能性を評価できないことです。読了後には、symlinkを許可するdirectory、拒否するtarget、CIで実行する回帰testを決められます。次の行動は、代表repositoryのlink一覧と追加directoryを棚卸しし、境界外の無害なfixtureで5種類のtoolをtestすることです。
この記事は脆弱性を再現して実dataへ到達する手順ではありません。隔離されたtest用directoryと無害なmarker fileだけを使います。最新版の正確なversion番号、配布channel、更新方法は公式releaseとClaude Code security文書で確認し、未更新環境を「設定だけで安全」と断定しません。企業ではversion pin、段階配布、rollback、検証結果を一つの変更記録へまとめます。
二つの修正点と残る運用責任を分ける
一つ目はtime-of-checkとtime-of-useの間にsymlink targetが変わる問題です。見かけのpathがworkspace内でも、実際のopen時に境界外へ解決されれば、最初の判定だけでは守れません。公式releaseはRead、Write、Editがpermission check後に交換されたsymlinkを追わないよう修正したと説明しています。利用者側では対応versionの配布を確認し、古いbinaryやbackground sessionが残っていないかを調べます。
二つ目は検索toolです。GrepとGlobは複数fileを探索するため、直接Readとは異なる経路でdeny対象へ触れる可能性があります。公式releaseはsymlinked search pathから到達したfileにもRead deny rulesを適用する修正を示しています。file名や一致断片だけでも秘密情報になり得るため、「書き込みを止めれば十分」としません。検索結果、error message、debug logへtarget pathや内容が漏れないことも確認します。
修正後も、利用者が明示的にworkspace外directoryを追加した場合、広いallow ruleを管理者が設定した場合、Bashやpluginなど別toolへ権限を与えた場合のriskは残ります。symlink対策を全toolのsandbox代替にせず、tool allowlist、restricted mode、managed settings、OS権限、container境界を重ねます。repositoryが生成するlinkと、利用者が手作業で追加するlinkを別管理にします。
許可・制限・禁止を6軸で判断する
- target:workspace内の固定targetか、homeや共有volumeなど境界外かを見ます。
- 作成者:build system、package manager、利用者、外部artifactを区別します。
- 変更可能性:session中にtargetや親directoryを交換できる主体を確認します。
- tool:Read、Write、Edit、Grep、Globとcommand実行を別々にtestします。
- data分類:targetにcredential、個人情報、別顧客dataがあるかを確認します。
- 実行環境:local、CI、container、self-hosted runnerでOS権限を分けます。
workspace内の生成物を指す固定linkで、作成工程とtargetがreview済みなら許可候補です。依存cacheなど読み取り専用の境界外directoryが必要なら、専用rootを追加し、writeを拒否し、content分類を限定します。home全体、credential directory、別顧客workspace、target不明、session中に第三者が交換できるlinkは禁止します。
monorepoでは便利さのためrootを広げがちですが、必要なsubdirectoryだけを追加します。CI runnerは短命にし、secretをfileへ残す時間を短くします。self-hosted runnerでは同じOS userが複数jobを扱わないよう分離します。link targetのcanonical pathをjob開始前後に記録し、想定外の変更があれば作業を中止します。
安全に回帰testする8手順
- 公式releaseで修正内容と対応versionを確認します。
- binary version、install元、release channel、実行中sessionを棚卸しします。
- 隔離directoryへworkspace内markerと境界外markerを作り、実dataを使いません。
- 固定link、境界外link、循環link、切れたlinkをtest fixtureとして準備します。
- Read、Write、Editを個別に実行し、境界外markerが読書きされないことを確認します。
- Grep、Globを個別に実行し、deny対象のfile名や内容が結果へ出ないことを確認します。
- 許可判定後にtargetを交換する競合testを安全なfixtureで実施します。
- 結果、version、settings revisionを保存し、更新ごとに自動再実行します。
成功条件は単なるerror発生ではありません。workspace内の許可fixtureは正常に扱え、境界外fixtureは拒否され、内容もfile名も漏れず、toolがhangしないことを確認します。循環linkと切れたlinkでは明確なerrorになり、無制限探索や大量logを起こさないことも見ます。testが本番secretへ近づかないよう専用userと一時containerを使います。
更新の段階配布では、代表OS、filesystem、container、IDE経路で同じsuiteを実行します。localで通ってもnetwork filesystemやrunnerで挙動が違う可能性があります。失敗時はlinkを全面削除する前に、対象workflowを停止し、version、settings、fixture、tool結果を保存して切り分けます。
運用チェックリストとHOLD条件
- 公式releaseを確認した
- 対応versionへ更新した
- 古いsessionを終了した
- install元を記録した
- symlink一覧がある
- canonical targetを確認した
- 境界外rootを最小化した
- Readをtestした
- Writeをtestした
- Editをtestした
- Grepをtestした
- Globをtestした
- 差し替え競合をtestした
- 実dataをfixtureに使わない
- 更新ごとの回帰testがある
HOLD条件は、実行version不明、公式修正を未確認、home全体を追加directoryへ指定、境界外secretで再現test、Grep・Glob未検証、古いbackground sessionが残る場合です。修正versionであることだけを理由に広い権限を許可せず、OS側の最小権限とrestricted modeも検討します。
よくある質問と次の行動
symlinkを削除すれば解決しますか?
riskは減りますが、必要なbuild linkまで壊す可能性があります。targetと用途を分類して限定します。
deny ruleだけで古いversionを使えますか?
推奨しません。公式修正を含むversionへ更新し、denyと回帰testを重ねます。
本番secretでtestしてよいですか?
いいえ。同じ境界構造を持つ無害なmarker fixtureを使い、実dataへ近づけません。
一次情報はClaude Code公式release、Claude Code security公式文書、設定範囲はsettings公式文書です。関連するrestricted mode、workspace trust、秘密情報を見せない設定も確認してください。Miraigentの無料診断では、許可rootと回帰testを60秒で整理します。
