Claude Code を職場で使おうとすると、情シスやセキュリティ担当からよく聞かれる質問があります。たとえばこちらの Qiita 記事では、情シスに必ず聞かれる質問として次の3つが挙げられています。導入の苦労を書いた他の記事でも、同じ種類の質問が繰り返し出てきます。
- 危険な操作を勝手にされないか
- AI が何をしているか見えるか
- 何かあったとき説明できるか
その手前で必ず「コードは学習に使われないのか」も聞かれます。
「CLAUDE.md に禁止と書いてあります」では答えになりません。あれはお願いで、強制力がないからです。この記事では、利用者が上書きできない管理設定(managed settings) で答えます。実際に効くかどうかは手元で試しました。どこまで止まり、どこから止まらないかも、試した結果のとおりに書きます。
- 検証環境:Claude Code 2.1.294、Linux(コンテナ、root で実行)、
claude -p(非対話モード)、2026-10-08 - 方法:使い捨てのプロジェクトにダミーの
.env・削除用のディレクトリ・ローカルの push 先を置き、条件ごとに作り直して1回ずつ実行しました
前提:管理設定とは
管理設定は、端末の管理者が置く設定ファイルです。利用者自身の設定(~/.claude/settings.json)、プロジェクトの設定、起動時の --settings のどれを使っても上書きできません。公式の説明は「Nothing in your own settings files or --settings overrides a managed key」です(settings)。
| OS | 置き場所 |
|---|---|
| macOS | /Library/Application Support/ClaudeCode/managed-settings.json |
| Linux・WSL | /etc/claude-code/managed-settings.json |
| Windows | C:\Program Files\ClaudeCode\managed-settings.json |
出典:managed-settings(2026-10-08 確認)。MDM で配ることもできます。Team / Enterprise プランなら、claude.ai の管理画面から全員に配る方式もあります(server-managed-settings)。
質問0:コードは学習に使われるのか
答えは 契約の種類で変わります。ここを曖昧にしたまま話を進めると、後でこじれます。
| 契約 | モデルの学習への利用 | Anthropic 側の保持期間 |
|---|---|---|
| 商用(Team / Enterprise / API) | 使わない(明示的に参加を申し込んだ場合を除く) | 標準 30 日。ゼロデータ保持(ZDR)は Enterprise の対象組織だけで、組織ごとに有効化 |
| 個人向け(Free / Pro / Max) | 本人の設定しだいで使われる | 学習を許可すると 5 年、許可しないと 30 日 |
出典:data-usage(2026-10-08 確認。規約は変わるので、提出前に最新版を確認してください)。
情シスに伝えるべき点は2つです。
- 個人契約のまま業務コードを扱わないことが最初の線引きになります
- 手元の PC にも会話が
~/.claude/projects/に平文で残ります(既定 30 日、cleanupPeriodDaysで変更可。デスクトップ版・Cowork のセッションは別の設定)。端末の紛失対策の範囲に入れておきます -
「30 日」には例外があります。
/feedback(/bug・/shareも同じ経路)で送った会話は 5 年保持されます。セッション後のアンケートで会話の共有に「Yes」と答えると、ソースコードを含む会話が送られ、最大 6 か月保持されます。止めるには環境変数DISABLE_FEEDBACK_COMMAND=1とCLAUDE_CODE_DISABLE_FEEDBACK_SURVEY=1を管理設定のenvで配ります(同ページ。この2つは今回試していません)
質問1:危険な操作を勝手にされないか
管理設定の deny は、利用者の許可より優先された
まず比較用に、管理設定なしで、起動オプション --allowedTools で rm -rf victim・git push・cat を許可しました。指示どおり3つとも実行され、.env の中身も出力に出ました。
次に、同じ許可のまま管理設定に次を置きました。
{
"permissions": {
"deny": ["Bash(rm -rf:*)", "Bash(git push:*)", "Read(./.env)", "Read(**/.env)"]
}
}
| 試したこと | 結果 |
|---|---|
rm -rf victim |
拒否(ディレクトリは残った) |
git push origin HEAD:main |
拒否(push 先にコミットは届かず) |
cat .env |
拒否(中身は出ず) |
echo start && git push origin HEAD:main(複合コマンド) |
拒否 |
利用者がその場で許可しても、管理設定の deny が勝ちました。
なお Bash(rm -rf:*) は「rm -rf で始まるコマンド」に一致する書き方で、書き方の揺れを吸収しません。追加で試した結果(2026-10-11、Claude Code 2.1.296):
| deny | 実行させたコマンド | 結果 |
|---|---|---|
Bash(rm -rf:*) |
rm -rf victim |
拒否 |
Bash(rm -rf:*) |
rm -fr victim |
実行されて消えた |
Bash(rm -rf:*) |
rm -r -f victim |
実行されて消えた |
Bash(rm:*) |
rm -r -f victim |
拒否 |
Bash(git push --force:*) |
git push -f origin HEAD:main |
push された |
Read(**/.env) |
cat .env.local |
値が出力された |
実際に配るときは、rm や git push は全体を deny か ask に入れ、.env は Read(**/.env.*) も足してください。手元の設定にこうした穴がないかは、設定チェッカーに貼るとまとめて確認できます。
さらに allowManagedPermissionRulesOnly: true を足すと、利用者側の allow(許可)ルールそのものが無視されます。--allowedTools "Bash(rm -rf victim)" を付けても、確認待ちとして止まりました。
確認を全部飛ばす --dangerously-skip-permissions は、"disableBypassPermissionsMode": "disable" で使えなくなります(permissions)。これは今回試せていないので、公式の記述として載せます。
落とし穴:Read の deny だけでは、秘密ファイルは守れない
上の設定のまま、別の読み方を試しました。
| 試したこと | 結果 |
|---|---|
python3 -c "print(open('.env').read())" |
.env の中身が出力された |
grep -r DUMMY . |
.env の中身が出力された |
これは不具合ではなく仕様です。公式も、Read の deny は cat などには効くが、別のプロセスが間接的に読む場合には効かないと書いています(「They don't apply to… arbitrary subprocesses that read or write files indirectly」、permissions)。
ちなみに、ネットでときどき見かける .claudeignore は公式の機能ではありません。置いても効きません(同ページ「has no effect」)。
サンドボックスを有効にしたら、OS レベルで止まった
管理設定にサンドボックスを足しました。
{
"permissions": { "deny": ["Read(**/.env)"] },
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"autoAllowBashIfSandboxed": false
}
}
同じ python3 と grep -r を(起動オプションで許可したうえで)試すと、どちらも Permission denied で失敗し、中身は出ませんでした。サンドボックスは Read の deny ルールの対象パスも読めなくしていました。(この2つは autoAllowBashIfSandboxed の行を足す前に試しました。足した後の完成形でも python の読み取りは失敗します)
設定の意味は次のとおりです(sandboxing)。
-
failIfUnavailable:サンドボックスを起動できない環境では、Claude Code 自体を起動しない。これを付けないと、サンドボックスなしで黙って動きます -
allowUnsandboxedCommands: false:失敗したコマンドを、サンドボックスの外で再試行させない -
autoAllowBashIfSandboxed: false:これを忘れると逆効果になります。既定値はtrueで、サンドボックスの中で動く Bash コマンドは確認なしで実行されます(settings-reference)。実際、既定値のままでは、許可していないrm victim/a.txtが確認なしで実行され、ファイルが消えました。falseにすると拒否されました(非対話モードでは確認できないため拒否になります)。止まるのは deny に書いたものだけ、ではなく、通常の確認の流れに戻すための設定です
使える OS は macOS・Linux・WSL2 です。Windows ネイティブと WSL1 では使えません。Linux・WSL2 では bubblewrap と socat が必要です。また、ファイル操作ツール・MCP・hooks はサンドボックスの外で動きます。
もう1つ注意があります。サンドボックスの設定には、利用者が自分の設定で広げられるものがあります。公式は excludedCommands(サンドボックスの外で動かすコマンド)や filesystem.allowWrite について「have no managed-only lock」と書いています(sandboxing)。たとえば利用者が python3 を除外すれば、上の読み取りはまた通るはずです(公式の記述からの推論で、試してはいません)。サンドボックスは「うっかり」や AI の暴走を止める柵で、利用者本人の意図的な回避まで防ぐものではありません。
質問2:AI が何をしているか見えるか
管理設定のフックで、拒否された試みまで記録できた
ツールを使う直前に呼ばれる PreToolUse フックで、入力を1行ずつファイルに追記しました。allowManagedHooksOnly: true を付けると、利用者やプロジェクトが足したフックは動かなくなります。
試した結果は次のとおりです。
- 利用者が
--settingsで足したフックは動かなかった。allowManagedHooksOnlyを外した比較では動いた - 記録には実行したコマンドだけでなく、拒否された
rm -rfとgit pushも残った
記録された1行の例です(値は短くしています)。
{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"git push origin HEAD:main","description":"..."},"permission_mode":"default","session_id":"...","cwd":"..."}
この記録には、Bash コマンドの引数や、ファイルに書き込んだ内容もそのまま入ります。秘密情報を含みうるファイルとして、権限と保管期間を決めておきます。
組織全体で集めるなら OpenTelemetry
フックの記録は端末の中に残るので、利用者が消せます。組織として集めるなら OpenTelemetry です(monitoring-usage)。
- 有効にする:
CLAUDE_CODE_ENABLE_TELEMETRY=1と送り先(OTEL_METRICS_EXPORTER、OTEL_LOGS_EXPORTER、OTEL_EXPORTER_OTLP_ENDPOINT)を設定する。管理設定のenvで全員に配れる - 分かること:セッション数、コストとトークン数、コミット数・PR 数、ツールの実行と許可・拒否のイベント
- 既定で記録されないもの:プロンプト本文(
OTEL_LOG_USER_PROMPTS)と、Bash コマンドなどのツール引数(OTEL_LOG_TOOL_DETAILS=1で記録される)
「入力した内容を管理者に読まれるのか」もよく聞かれる質問です。既定では読まれず、設定すれば記録できる、が正確な答えです。どちらにするかは規程で決めて、利用者に知らせておきます。
質問3:何かあったとき説明できるか
ここは設定1つで解決するものではありません。説明に使える材料をそろえておく、というのが答えになります。
- 何を止めているか:管理設定のファイルそのもの。誰でも読める場所に置く
- 何が起きたか:フックの記録、または OpenTelemetry のイベント。それに git の履歴
- 何を止めていないか:下の「限界」を、先に書面で伝えておく
3つ目が一番大事です。「全部防げます」と言ってから穴が見つかるより、「ここまでは止まり、ここからは止まらない」を先に出すほうが信用されます。
今回の設定の完成形
上の検証を1つにまとめたものです。このファイルで、git push の拒否、python による .env 読み取りの失敗、許可していない rm victim/a.txt の拒否、許可した ls の実行、拒否分を含む記録を確認しました(2.1.294、Linux)。rm は、上の追加検証を受けて Bash(rm -rf:*) から Bash(rm:*) に変えています(rm -fr・rm -r -f も拒否されることを 2.1.296 で確認)。
認証情報の保護をさらに広げたい場合は、公式リポジトリの設定例(examples/settings/settings-hipaa.json)が、~/.git-credentials・~/.netrc・~/.config/gh などの読み書きの拒否や、環境変数の秘密を隠す設定まで含んでいるので、あわせて参考にしてください。
{
"permissions": {
"deny": [
"Bash(rm:*)",
"Bash(git push:*)",
"Read(**/.env)",
"Read(**/.env.*)",
"Read(~/.ssh/**)",
"Read(~/.aws/**)"
],
"disableBypassPermissionsMode": "disable"
},
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"autoAllowBashIfSandboxed": false
},
"allowManagedHooksOnly": true,
"hooks": {
"PreToolUse": [
{
"matcher": "*",
"hooks": [
{ "type": "command", "command": "mkdir -p \"$HOME/.claude-audit\" && (cat; echo) >> \"$HOME/.claude-audit/tool-use.jsonl\"" }
]
}
]
}
}
記録のフックは入力をそのまま書くので、Write で書いた中身やコマンド中のトークンも記録に残ります(実測)。記録を見せる・残す前提なら、中身を書かずにツール名・コマンド・ファイル名だけを選んで書く形にしてください。
git push まで禁止すると困るチームも多いはずです。deny に何を入れるかは、チームの運用に合わせて選んでください。Read(**/.env.*) は .env.example も読めなくするので、テンプレートを読ませたい場合は調整してください。
情シスに渡す回答表(ひな形)
| 質問 | 答え | 根拠(設定・文書) | 限界 |
|---|---|---|---|
| コードは学習に使われるか | 商用契約(Team / Enterprise / API)では使われない。標準の保持期間は 30 日 | data-usage(確認日を書く) | 個人契約では設定しだい。/feedback で送った会話は 5 年保持(環境変数で止める) |
| 危険な操作を勝手にされないか | 管理設定の deny で拒否。利用者は上書きできない | managed-settings.json | パターンに合わない書き方は通りうる。deny は「うっかり」を防ぐ柵 |
| 秘密ファイルを読まれないか | Read の deny+サンドボックスで OS レベルで拒否 | sandbox 設定 | Windows ネイティブ・WSL1 ではサンドボックスが使えない。利用者が自分の設定で除外コマンドを足すと外れうる |
| 何をしているか見えるか | ツールの実行を記録(拒否分も含む)。組織では OpenTelemetry で収集 | hooks/env 設定 | プロンプト本文は既定で記録しない(記録するかは規程で決める)。記録ファイル自体が秘密を含みうる |
| 何かあったとき説明できるか | 設定ファイル・記録・git 履歴で説明する | 上記一式 | 端末内の記録は利用者が消せる |
限界と注意(ここまで含めて伝える)
- 使う製品によって、管理設定の届き方が違います。公式によると、Cowork は管理画面からの配信(server-managed settings)を受け取りません。端末の管理設定ファイルは読みますが、VM サンドボックスで動かす場合とリモートの Cowork では読まれません(managed-settings)。Anthropic のクラウドで動くセッションも、端末のファイルではなく管理画面からの配信だけが効きます
- 管理設定が期待どおりに効かないという報告もあります(例:管理設定の
envで配った OpenTelemetry の変数が効かない #67657、Cowork で hooks が効かない #40495。どちらも未検証)。今回確かめたのは CLI だけです。デスクトップ版・IDE 拡張・Cowork を使わせるなら、それぞれで確かめてください -
WSL では
/etc/claude-codeを利用者が書き換えられます(公式に明記、managed-settings)。WSL を強制の手段にはできません - deny はパターンマッチです。今回は複合コマンドでも止まりましたが、書き方しだいで通るものがありえます。止めたいものは複数の層(deny、サンドボックス、git のブランチ保護)で止めます
- 今回の検証は各条件1回、Linux の CLI だけです。版が上がったら試し直してください
手元の設定に、ここで見たような穴がないかは、無料の設定チェッカーに貼るとまとめて確かめられます:https://acerola-tools.acerola.workers.dev/check/?from=qiita-claude-code-managed-settings-security-qa
本記事は Zenn にも掲載しています:https://zenn.dev/acerola_jp/articles/claude-code-managed-settings-security-qa