# Agent Permissions Index > Aggregate security data on how developers configure AI coding agents (Claude Code, Codex CLI, Gemini CLI, Cursor) in 14,111 unique public GitHub config files. Snapshot 2026-10-20, refreshed weekly. Aggregates only; no repositories are named. Stats licensed CC BY 4.0. ## Key pages - [Overview](https://agent-permissions-index.vercel.app/): headline stats per tool - [Security leaderboard](https://agent-permissions-index.vercel.app/leaderboard): tools ranked by share of configs with a high-risk setting - [Config grader](https://agent-permissions-index.vercel.app/grade): paste a JSON config, get an A–F grade (runs in the browser) - [Methodology](https://agent-permissions-index.vercel.app/methodology): collection, de-duplication, metric definitions, limits - [MCP server](https://agent-permissions-index.vercel.app/mcp-docs): remote MCP at https://agent-permissions-index.vercel.app/mcp with tools grade_config, get_index_stats, get_leaderboard ## Guides - [Claude Code permissions: deny rules and a safe settings.json](https://agent-permissions-index.vercel.app/guides/claude-code): How Claude Code permissions work, what 85.6% of public configs get wrong, and a safe .claude/settings.json you can copy. - [Codex CLI permissions: approval_policy, sandbox_mode and full-auto bypass](https://agent-permissions-index.vercel.app/guides/codex): How Codex CLI approval and sandbox settings work, why 12.9% of public configs that set them use full bypass, and a safe config.toml. - [Cursor mcp.json API keys: keep secrets out of .cursor/mcp.json](https://agent-permissions-index.vercel.app/guides/cursor): 7.8% of public Cursor .cursor/mcp.json files contain a credential-looking value. How to keep keys out of mcp.json, with a safe example. - [Gemini CLI YOLO mode, approval modes and a safe settings.json](https://agent-permissions-index.vercel.app/guides/gemini-cli): 42.4% of public Gemini CLI configs that set permissions turn on YOLO/auto-accept. What the settings do and a safe .gemini/settings.json. ## Answers - [How to add deny rules in Claude Code (settings.json examples)](https://agent-permissions-index.vercel.app/learn/claude-code-deny-rules): Add permissions.deny to .claude/settings.json to block reading .env files, git push and self-editing. 85.6% of public configs have none. - [Is Codex full-auto safe? --full-auto vs --yolo explained](https://agent-permissions-index.vercel.app/learn/is-codex-full-auto-safe): Codex's Auto preset keeps a sandbox, but --yolo / danger-full-access removes it. 12.9% of public Codex configs that set permissions use full bypass. - [How to keep API keys out of .cursor/mcp.json](https://agent-permissions-index.vercel.app/learn/cursor-mcp-json-api-keys): Use ${env:NAME} or envFile instead of pasting tokens into Cursor's mcp.json. 7.8% of public .cursor/mcp.json files contain a credential-looking value. - [What is Gemini CLI YOLO mode? (and how to use it safely)](https://agent-permissions-index.vercel.app/learn/what-is-gemini-cli-yolo-mode): YOLO mode auto-approves every Gemini CLI tool call. 42.4% of public configs that set permission keys turned it on (small sample). - [How to stop Claude Code from reading your .env file](https://agent-permissions-index.vercel.app/learn/stop-claude-code-reading-env): Add Read(./.env) and Read(./.env.*) to permissions.deny in .claude/settings.json. Only 7% of public Claude Code configs with permissions do. - [A safe Claude Code settings.json template (copy and paste)](https://agent-permissions-index.vercel.app/learn/claude-code-settings-json-template): A starting .claude/settings.json with allow, ask and deny lists. 24% of public configs allow a wildcard interpreter and 85.6% have no deny rules. - [Codex sandbox modes explained: read-only, workspace-write, danger-full-access](https://agent-permissions-index.vercel.app/learn/codex-sandbox-modes-explained): What each Codex sandbox_mode allows and when to use it. 18% of public Codex configs that set permissions use danger-full-access. - [Gemini CLI excludeTools examples: block shell commands and tools](https://agent-permissions-index.vercel.app/learn/gemini-cli-exclude-tools): Block tools with tools.exclude, MCP tools with excludeTools, and shell commands with a policy rule. 20% of public Gemini configs with permission keys block anything. - [Is it safe to commit .mcp.json? (API keys in MCP configs)](https://agent-permissions-index.vercel.app/learn/is-it-safe-to-commit-mcp-json): Committing .mcp.json is fine if it has no secrets. 1.9% of public project .mcp.json files and 7.8% of .cursor/mcp.json files contain a credential-looking value. ## Claude Code: what deny rules target Of 4831 unique configs with permissions (694 with any deny rule): - .env files: 339 (7% of configs with permissions; 48.8% of those with deny rules) - secrets / credentials paths: 152 (3.1% of configs with permissions; 21.9% of those with deny rules) - .claude settings: 31 (0.6% of configs with permissions; 4.5% of those with deny rules) - git push: 292 (6% of configs with permissions; 42.1% of those with deny rules) - rm (incl. rm -rf): 331 (6.9% of configs with permissions; 47.7% of those with deny rules) - all five: 5 ## Leaderboard (higher = safer) 1. Claude Code: 97.1 (n=5963, high-risk 2.9%, deny rules 11.6% of unique configs / 14.4% of those setting permissions) 2. Gemini CLI: 93.4 (n=1377, high-risk 6.6%, deny rules 1.2% of unique configs / 20% of those setting permissions, small sample) 3. Codex CLI: 92.9 (n=4194, high-risk 7.1%, deny rules n/a (no deny setting)) 4. Cursor: 92.2 (n=1427, high-risk 7.8%, deny rules n/a (no deny setting)) A high score does not mean locked down. The score only counts settings that open the door wide (bypass, unrestricted shell, hardcoded credentials). Deny rules are what stop an agent that decides to go further, and most configs have none. "Has deny rules" = % of unique configs with at least one deny rule (Claude Code permissions.deny, Gemini CLI excludeTools). Codex and Cursor have no deny-list setting, so it is n/a for them. Not part of the score. ## Scoring Score = 100 minus the % of unique public configs for that tool with at least one high-risk setting: full bypass / YOLO mode, unrestricted shell (any command, or Codex danger-full-access), or a hardcoded credential-looking value. Identical configs are counted once. Higher is safer. Cursor's mcp.json has no permission model, so Cursor can only fail on credentials; deny-rule coverage is shown for context but not scored, since only some tools support it. ## Per-tool stats (unique configs) ### Claude Code (.claude/settings.json) - Unique public configs analyzed: 5,963 - Configs with a permissions block: 4,831 - …with no deny rules: 85.6% - …allowing a wildcard interpreter (python, node, npx…): 24% - …allowing curl/wget to any URL: 12.5% - …allowing rm with any arguments: 6.7% - …allowing any shell command (Bash, Bash(*)): 2.7% - …with bypassPermissions as default mode: 1% - …with a deny rule covering .env files: 7% (339 of 4,831) - …with a deny rule covering secrets / credentials paths: 3.1% (152 of 4,831) - …with a deny rule covering .claude settings: 0.6% (31 of 4,831) - …with a deny rule covering git push: 6% (292 of 4,831) - …with a deny rule covering rm (incl. rm -rf): 6.9% (331 of 4,831) - …covering all five (.env, secrets, .claude, git push, rm): 5 of 4,831 - Leaderboard: #1 of 4 on the safety leaderboard (score 97.1) Risky patterns: - No deny rules: Without deny, nothing stops the agent reading .env files or pushing to git once a broad allow matches. - Bash(python3:*), Bash(node:*), Bash(npx:*): A wildcard interpreter can run any code, so it is effectively an unrestricted shell. Allow named scripts instead. - Bash(curl:*) / Bash(wget:*): Lets the agent send data to any URL. Use WebFetch(domain:...) for the domains you need. - Broad Edit/Write without denying .claude/**: The agent can rewrite settings.json, including your deny rules. Only 31 of 694 configs that have deny rules protect .claude. Deny Edit(./.claude/**) and Write(./.claude/**). - defaultMode: bypassPermissions: Skips permission prompts. Current Claude Code ignores bypassPermissions in project settings (set it in ~/.claude/settings.json if you really want it), but older versions honored it from the repo, and deny rules still apply in every mode. Safe example: ```json { "permissions": { "allow": [ "Bash(npm run test:*)", "Bash(npm run lint:*)", "Bash(git status)", "Bash(git diff:*)" ], "deny": [ "Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)", "Edit(./.claude/**)", "Write(./.claude/**)", "Bash(git push:*)", "Bash(rm -rf:*)" ] } } ``` FAQ: Q: Where do Claude Code permissions live? A: In the permissions block of .claude/settings.json (shared with the project), .claude/settings.local.json (personal, usually gitignored) or ~/.claude/settings.json (user-wide). Managed settings set by an organization override all of them. Q: Do deny rules override allow rules in Claude Code? A: Yes. Claude Code evaluates deny, then ask, then allow, and the first match wins. An allow rule can't carve an exception out of a deny rule, and deny rules still apply in bypassPermissions mode. Q: How many Claude Code configs have deny rules? A: In the index, 14.4% of 4,831 unique public configs with a permissions block have at least one deny rule; 85.6% have none. Q: Is Bash(python3:*) safe to allow? A: No. A wildcard interpreter can run any code, so it is effectively an unrestricted shell. Allow named scripts such as Bash(npm run test *) instead. ### Codex CLI (.codex/config.toml) - Unique public configs analyzed: 4,194 - Configs that set approval_policy or sandbox_mode: 1,200 - …full bypass (never + danger-full-access): 12.9% - …sandbox_mode = danger-full-access: 18% - …approval_policy = never: 22.2% - All configs with a credential-looking literal: 2.1% - Configs that define MCP servers: 55.4% - Leaderboard: #3 of 4 on the safety leaderboard (score 92.9) Risky patterns: - approval_policy = "never" + sandbox_mode = "danger-full-access": No prompts and no sandbox: the agent can run anything on your machine with your permissions. - danger-full-access as a default: Use it only inside a disposable container or VM. workspace-write covers most coding work. - Tokens pasted into [mcp_servers.*.env]: Committed config files leak keys. Reference environment variables instead, and rotate any key that was committed. - Permissive profiles: A yolo profile in a shared config is one flag away. Keep it in your personal ~/.codex/config.toml, not the repo. Safe example: ```toml approval_policy = "on-request" sandbox_mode = "workspace-write" [sandbox_workspace_write] network_access = false [mcp_servers.github] command = "npx" args = ["-y", "@modelcontextprotocol/server-github"] env_vars = ["GITHUB_TOKEN"] # forwarded from your shell, not hardcoded ``` FAQ: Q: What does the Auto preset (--full-auto) do in Codex? A: The Auto preset runs with sandbox_mode workspace-write and approval_policy on-request: Codex edits and runs commands inside the workspace and asks before writing outside it or using the network. The network is off by default in workspace-write. Q: What is Codex --yolo? A: --yolo is an alias for --dangerously-bypass-approvals-and-sandbox: no sandbox and no approval prompts. OpenAI's docs label it elevated risk and not recommended outside an isolated container. Q: How common is full bypass in public Codex configs? A: 12.9% of 1,200 unique public configs that set approval_policy or sandbox_mode combine approval_policy = "never" with sandbox_mode = "danger-full-access". Q: Can I grade a Codex config.toml? A: Not in the web grader yet; it reads JSON. Use the checklist on this page. ### Cursor (.cursor/mcp.json) - Unique public .cursor/mcp.json files analyzed: 1,427 - …with at least one credential-looking value: 7.8% - …defining at least one MCP server: 99.2% - Leaderboard: #4 of 4 on the safety leaderboard (score 92.2) Risky patterns: - API keys in env or headers: Anything committed to a public repo is scraped within minutes. Rotate the key, then switch to ${env:NAME}. - Unknown MCP servers via npx -y: npx -y runs the latest published version without review. Pin versions for servers you depend on. - Auto-run settings in the app: Cursor's auto-run/allowlist lives in app settings, not this file. The index can't see it, so check it yourself. Safe example: ```json { "mcpServers": { "github": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-github" ], "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${env:GITHUB_TOKEN}" } } } } ``` FAQ: Q: Can I use environment variables in .cursor/mcp.json? A: Yes. Cursor resolves ${env:NAME} in command, args, env, url and headers. Local (stdio) servers also accept envFile, e.g. "${workspaceFolder}/.env". Q: How many public Cursor mcp.json files contain a key? A: 7.8% of 1,427 unique public .cursor/mcp.json files contain at least one credential-looking value. The check is a heuristic and has false positives. Q: I committed a key in mcp.json. Is deleting it enough? A: No. It stays in git history and may already have been scraped. Rotate the key first, then switch the file to ${env:NAME}. ### Gemini CLI (.gemini/settings.json) - Unique public configs analyzed: 1,377 - Configs that set any permission keys: 85 (small sample) - …with YOLO / auto-accept on: 42.4% - …allowing the shell tool unrestricted: 10.6% - …with any excluded tools: 20% - All configs with a credential-looking literal: 3.4% - Leaderboard: #2 of 4 on the safety leaderboard (score 93.4, small sample) Risky patterns: - YOLO / auto-accept committed to the repo: Older versions honored these keys from a committed settings.json, so everyone who cloned the repo ran with no prompts. Remove them and use --approval-mode=yolo only per session, inside a sandbox (--sandbox). - run_shell_command allowed without arguments: Allows any shell command. List specific commands like run_shell_command(npm test). - No tools.exclude: Exclude the destructive commands you never want run automatically. - API keys in mcpServers env: Use $VAR references so the key stays in your environment. Safe example: ```json { "tools": { "core": [ "read_file", "glob", "search_file_content", "replace", "write_file", "run_shell_command(git status)", "run_shell_command(npm test)" ], "exclude": [ "run_shell_command(rm)", "run_shell_command(git push)" ] }, "mcpServers": { "github": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-github" ], "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "$GITHUB_TOKEN" } } } } ``` FAQ: Q: What is Gemini CLI YOLO mode? A: An approval mode that auto-approves every tool call, including shell commands. Current versions only allow it from the command line with --approval-mode=yolo, or the deprecated --yolo flag. Q: Can I set YOLO mode in settings.json? A: Not in current versions. general.defaultApprovalMode accepts default, auto_edit and plan. Older configs used yolo, autoAccept or approvalMode keys, and the index still counts those. Q: How common is YOLO mode in public Gemini configs? A: 42.4% of the 85 unique public configs that set any permission keys turn on YOLO or auto-accept. That's a small sample. ### How do I add deny rules in Claude Code? Add a permissions.deny array to .claude/settings.json (or settings.local.json). Each entry is a rule like Read(./.env) or Bash(git push *). Claude Code checks deny before ask and allow, so a matching deny blocks the call even if an allow rule also matches. #### Minimal example ``` { "permissions": { "deny": [ "Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)", "Edit(./.claude/**)", "Write(./.claude/**)", "Bash(git push *)", "Bash(rm -rf *)" ] } } ``` #### How precedence works Rules are evaluated deny → ask → allow, and the first match wins regardless of how specific the rule is. A broad deny like Bash(aws *) blocks Bash(aws s3 ls) even if that is explicitly allowed. A bare tool name in deny (for example WebFetch) removes the tool entirely. Deny rules apply in every permission mode, including bypassPermissions. #### Which rules to deny first Secrets (Read(./.env), Read(./.env.*), Read(./secrets/**)), the settings directory (Edit(./.claude/**), Write(./.claude/**)), so the agent can't rewrite its own deny list, and irreversible commands such as git push and rm -rf. Use ask instead of deny for commands you want to approve case by case. #### What public configs do Of 4,831 unique public Claude Code configs with a permissions block, 85.6% have no deny rules. 24% allow a wildcard interpreter and 12.5% allow curl or wget to any URL, which are the cases where deny rules matter most. #### What existing deny rules cover Of the 694 unique configs that have deny rules: .env files 339 (48.8%), secrets / credentials paths 152 (21.9%), .claude settings 31 (4.5%), git push 292 (42.1%), rm (incl. rm -rf) 331 (47.7%). Only 5 cover all five. As a share of all 4,831 configs with permissions, only 7% deny .env. #### Rule syntax note Current docs write wildcards with a space, e.g. Bash(npm run *). Many existing configs use the older colon form, e.g. Bash(npm run:*). Sources: https://code.claude.com/docs/en/permissions, https://code.claude.com/docs/en/settings-reference ### Is Codex full-auto safe? The Auto preset (workspace-write sandbox + on-request approvals) is reasonably safe for a version-controlled repo: Codex can edit and run commands only inside the workspace, the network is off by default, and it asks before going further. --yolo (--dangerously-bypass-approvals-and-sandbox) is not: it removes both the sandbox and the prompts. #### The two settings that matter sandbox_mode decides what Codex can technically do (read-only, workspace-write, danger-full-access). approval_policy decides when it stops to ask (on-request or never; the old untrusted value is retired and can stop Codex from starting). #### Common combinations ``` # Auto preset (recommended for repos) sandbox_mode = "workspace-write" approval_policy = "on-request" # Read-only CI sandbox_mode = "read-only" approval_policy = "never" # Full bypass (what --yolo does). Use only in a disposable container sandbox_mode = "danger-full-access" approval_policy = "never" ``` #### What public configs do Of 1,200 unique public Codex configs that set either key, 18% use danger-full-access, 22.2% set approval_policy = "never", and 12.9% combine both (full bypass). #### Safer alternatives to full access Keep workspace-write and enable network only if you need it ([sandbox_workspace_write] network_access = true). Workspace-write still protects .git, .codex and .agents as read-only. If the host can't run the sandbox, run Codex in a dev container and use danger-full-access only inside it, with trusted repos. Sources: https://learn.chatgpt.com/docs/agent-approvals-security, https://developers.openai.com/codex/config-reference ### How do I keep API keys out of .cursor/mcp.json? Reference environment variables with ${env:NAME} in env, headers, url, args or command, or point a local (stdio) server at an envFile. Keep the actual key in your shell profile or a gitignored .env. #### Local (stdio) server ``` { "mcpServers": { "github": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-github" ], "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${env:GITHUB_TOKEN}" } } } } ``` #### Remote server with a header ``` { "mcpServers": { "remote": { "url": "https://api.example.com/mcp", "headers": { "Authorization": "Bearer ${env:MY_SERVICE_TOKEN}" } } } } ``` #### Using an envFile Local (stdio) servers accept "envFile": "${workspaceFolder}/.env". Remote servers don't support envFile, so use ${env:NAME} for those. Add .env to .gitignore. #### What public configs do 7.8% of 1,427 unique public .cursor/mcp.json files contain at least one value that looks like a real credential. For comparison: Gemini CLI settings 3.4%, Codex config.toml 2.1%. The detector is a heuristic and has false positives. #### If a key was already committed Rotate it first. Deleting it from the file leaves it in git history, and public repos are scanned for keys continuously. Sources: https://cursor.com/docs/mcp ### What is Gemini CLI YOLO mode? YOLO is a Gemini CLI approval mode that auto-approves every tool call, including shell commands and file writes. Current versions enable it only from the command line (--approval-mode=yolo, or the deprecated --yolo / -y). It can't be set as the default in settings.json. #### Approval modes default prompts for each tool call. auto_edit auto-approves edit tools (replace, write_file) and prompts for others. plan is read-only. yolo approves everything. In settings.json, general.defaultApprovalMode accepts default, auto_edit or plan. #### Using it more safely ``` gemini --sandbox --approval-mode=yolo ``` #### Restricting tools instead ``` { "general": { "defaultApprovalMode": "auto_edit" }, "tools": { "core": [ "read_file", "glob", "search_file_content", "replace", "write_file", "run_shell_command(git status)", "run_shell_command(npm test)" ] } } ``` #### What public configs do Older configs could switch YOLO/auto-accept on from a committed settings file. Of 85 unique public Gemini CLI configs that set any permission keys, 42.4% did. That is a small sample, so treat it as indicative. Organizations can disable YOLO at the policy level. Sources: https://geminicli.com/docs/cli/settings/, https://geminicli.com/docs/cli/cli-reference/, https://geminicli.com/docs/cli/enterprise/ ### How do I stop Claude Code from reading my .env file? Add Read(./.env) and Read(./.env.*) to the permissions.deny array in .claude/settings.json. Deny rules are checked before allow rules, so the read is blocked even if something broader is allowed. Also deny Edit and Write on .claude/** so the agent can't remove the rule. #### The rules ``` { "permissions": { "deny": [ "Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)", "Read(~/.aws/**)", "Edit(./.claude/**)", "Write(./.claude/**)" ] } } ``` #### Read rules don't cover the shell A Read deny stops the Read tool. It doesn't stop a Bash command like cat .env if you've allowed broad shell access. Avoid wildcard rules such as Bash(cat *) or Bash(python3 *), or add matching Bash denies. For stronger isolation, run Claude Code in a sandbox or container that doesn't have the secrets mounted. #### Where to put it Use .claude/settings.json if the whole team should get the rule (commit it). Use ~/.claude/settings.json to apply it to every project on your machine. #### How many configs do this Of 4,831 unique public Claude Code configs with a permissions block, 339 (7%) deny reading .env files. Even among the 694 configs that have any deny rule, only 48.8% cover .env. Sources: https://code.claude.com/docs/en/permissions, https://code.claude.com/docs/en/settings ### What is a safe Claude Code settings.json? Allow the specific commands your project runs (tests, lint, build), put risky but sometimes needed commands in ask, and deny secrets, the .claude directory and destructive commands. Avoid wildcard interpreter rules like Bash(python3 *), which allow any code. #### Template ``` { "permissions": { "allow": [ "Bash(npm run test *)", "Bash(npm run lint)", "Bash(npm run build)", "Bash(git status)", "Bash(git diff *)" ], "ask": [ "Bash(git commit *)", "Bash(npm install *)", "WebFetch" ], "deny": [ "Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)", "Edit(./.claude/**)", "Write(./.claude/**)", "Bash(git push *)", "Bash(rm -rf *)", "Bash(curl *)", "Bash(wget *)" ] } } ``` #### Why each list looks like this allow is for commands you'd approve every time anyway. ask is for things you want to see before they run. deny always wins, in every permission mode, so it's where secrets and irreversible commands go. Change the npm commands to whatever your project uses. #### Common mistakes in public configs Of 4,831 unique public configs with permissions: 24% allow a wildcard interpreter (python, node, npx and similar), 12.5% allow curl or wget to any URL, 6.7% allow rm with a wildcard, and 1% turn on bypass mode in the file. #### Check your own file Paste it into the grader on this site. It runs in your browser and the config isn't uploaded. Sources: https://code.claude.com/docs/en/permissions, https://code.claude.com/docs/en/settings ### What are the Codex sandbox modes? read-only lets Codex read files but not change them or use the network. workspace-write lets it edit files and run commands inside the workspace, with network off by default. danger-full-access removes the sandbox entirely. Set it with sandbox_mode in config.toml or --sandbox on the command line. #### Config ``` # ~/.codex/config.toml or .codex/config.toml sandbox_mode = "workspace-write" approval_policy = "on-request" [sandbox_workspace_write] network_access = false ``` #### read-only Good for reviewing code, answering questions about a repo, and CI jobs that only report. Codex asks before doing anything that needs more access (unless approval_policy is never). #### workspace-write The default for most repo work. Writes outside the workspace and network access need approval. Folders like .git and .codex stay read-only even inside the workspace. #### danger-full-access No sandbox. Combined with approval_policy = "never" it's the same as --yolo. Only use it inside a container or VM you can throw away. #### What public configs do Of 1,200 unique public Codex configs that set sandbox_mode or approval_policy, 216 (18%) use danger-full-access and 155 (12.9%) pair it with approval_policy = "never". Sources: https://developers.openai.com/codex/config-reference, https://learn.chatgpt.com/docs/agent-approvals-security ### How do I block tools or shell commands in Gemini CLI? To hide a whole built-in tool, list it in tools.exclude in .gemini/settings.json. To hide tools from one MCP server, use excludeTools on that server's entry. To block specific shell commands like rm -rf, current docs say to use a Policy Engine rule; run_shell_command(...) entries in tools.exclude still work but are deprecated for that. #### Hide whole tools ``` { "tools": { "exclude": [ "web_fetch", "google_web_search" ] } } ``` #### Hide tools from an MCP server ``` { "mcpServers": { "github": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-github" ], "excludeTools": [ "delete_repository", "push_files" ] } } } ``` #### Block shell commands (Policy Engine) Put .toml files in ~/.gemini/policies/. All of them are loaded and combined, and the highest-priority matching rule decides. ``` # ~/.gemini/policies/deny.toml [[rule]] toolName = "run_shell_command" commandPrefix = "rm -rf" decision = "deny" priority = 100 [[rule]] toolName = "run_shell_command" commandPrefix = "git push" decision = "deny" priority = 100 ``` #### The older way (deprecated for commands) Before the Policy Engine, the docs used run_shell_command() entries in tools.exclude. Matching is by prefix, chained commands (&&, ||, ;) are split and checked separately, and exclude wins over tools.core. Very old configs used a flat top-level excludeTools key; current docs only use excludeTools inside an MCP server entry. ``` { "tools": { "core": [ "run_shell_command" ], "exclude": [ "run_shell_command(rm)" ] } } ``` #### Allowlist instead tools.core lists the only built-in tools the CLI may use. Setting it to anything turns off every built-in tool you don't list, including read_file and write_file, so list those too. A prefix blocklist can miss variants and scripts that call the blocked command, so pair it with --sandbox for real isolation. #### What public configs do Of 85 unique public Gemini CLI configs that set any permission keys, 17 (20%) exclude something and 36 (42.4%) turn on YOLO or auto-accept. The sample is small. Separately, 3.4% of 1,377 unique Gemini settings files contain a credential-looking value. Sources: https://geminicli.com/docs/reference/configuration/, https://geminicli.com/docs/tools/shell/, https://geminicli.com/docs/reference/policy-engine/ ### Is it safe to commit .mcp.json to git? Yes, as long as it doesn't contain secrets. Claude Code expands ${VAR} and ${VAR:-default} in .mcp.json, so reference keys from the environment instead of pasting them. Anyone who clones the repo can read the file. #### Use environment variables ``` { "mcpServers": { "github": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-github" ], "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" } }, "api": { "type": "http", "url": "https://api.example.com/mcp", "headers": { "Authorization": "Bearer ${API_KEY}" } } } } ``` #### Syntax differs by tool Claude Code's .mcp.json uses ${VAR} or ${VAR:-default}, expanded in command, args, env, url and headers. Cursor's .cursor/mcp.json uses ${env:VAR}. In Claude Code, a remote server entry needs "type": "http", and credential variables such as ANTHROPIC_API_KEY read as empty in a remote server's url and headers, so use a variable name of your own. #### What public configs do 22 of 1,150 unique public .mcp.json files (1.9%) and 112 of 1,427 .cursor/mcp.json files (7.8%) contain at least one credential-looking value. The detector is a heuristic and has false positives. #### If you already committed a key Rotate it with the provider first. Removing it from the file doesn't remove it from git history. Sources: https://code.claude.com/docs/en/mcp, https://cursor.com/docs/mcp ## Limits Public repos only (skew toward templates, demos, dotfiles); GitHub search ranking decides what is returned; credential detection is a heuristic; tools have different permission models.