Stop AI coding tools from reading your API keys and secrets: settings for Claude Code, Codex and Gemini CLI

General Published:

Settings that keep .env files and credentials away from Claude Code, Codex and Gemini CLI, what to do after a leak, and how to keep secrets out of the repository altogether.

Verified on Sep 7, 2026 These tools change quickly. Please also check the latest official documentation.
Contents
  1. What can leak
  2. Claude Code: deny rules
  3. Codex: rely on placement, not the sandbox
  4. Gemini CLI: ignore files and GEMINI.md
  5. The real fix: keep secrets out of the repository
  6. MCP servers
  7. CI and cloud runs
  8. After a leak
  9. Summary

A coding agent reads .env or config/secrets.yml whenever it decides that is needed for the task. What it reads is sent to the API and kept in logs and history. "It is in .gitignore, so it is fine" is a misconception: what Git tracks and what the agent reads are two different things.

This article gives per-tool settings that keep secrets away from Claude Code, Codex and Gemini CLI, and the tool-independent fix that actually works.

KEY POINT

What you will learn

  • Blocking reads of .env and similar files in each of the three tools
  • Leak paths through MCP servers, hooks and CI, and how to close them
  • Keeping secrets out of the repository, and what to do after a leak

What can leak

PathExamples
File reads.env, *.pem, credentials.json, ~/.aws/credentials
Command outputenv, printenv, cat ~/.ssh/id_rsa, docker inspect
Git historySecrets committed in the past show up in git log -p
MCP serversTokens passed to a server, and whatever the server returns
Context filesURLs or passwords accidentally written into CLAUDE.md

Claude Code: deny rules

deny in .claude/settings.json always beats allow and cannot be overridden by personal settings, so put it in the shared file:

{
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./**/*.pem)",
      "Read(./**/*.key)",
      "Read(./secrets/**)",
      "Read(~/.aws/**)",
      "Read(~/.ssh/**)",
      "Bash(env)",
      "Bash(printenv:*)",
      "Bash(cat ~/.aws:*)",
      "Bash(cat ~/.ssh:*)"
    ]
  }
}

Bash deny rules match the beginning of the command string, so alternative spellings slip past them. Denying Read on the files is the reliable part. The full rule syntax is in Claude Code permissions in settings.json.

A PreToolUse hook can add a second check on the path being read:

#!/usr/bin/env bash
# .claude/hooks/guard-secrets.sh
file=$(jq -r '.tool_input.file_path // empty')
case "$file" in
  *.env|*.env.*|*.pem|*.key|*/secrets/*|*/.aws/*|*/.ssh/*)
    echo "Reading secret files is blocked: $file" >&2
    exit 2 ;;
esac
exit 0

Codex: rely on placement, not the sandbox

Codex's sandbox restricts writes and network access, but it does not restrict reading files inside the workspace, and there is no per-file read deny. Two things help:

  1. Keep secrets outside the workspace. Put .env in a location such as ~/.config/myapp/.env and have the application load it by path.
  2. Say it in AGENTS.md. "Do not read .env or anything under secrets/; use .env.example for the variable names." It is instruction-based and therefore not a guarantee, but it reduces accidental reads.

Even read-only mode can read. Placement is the real control; see Codex CLI approval modes versus sandbox modes.

Gemini CLI: ignore files and GEMINI.md

Gemini CLI can respect .gitignore when exploring files (see the fileFiltering settings for your version), and it reads a .geminiignore file:

# .geminiignore
.env
.env.*
secrets/
*.pem
*.key

Ignore rules apply to file discovery (search and listing) and may not block a read of an explicitly named path. State the rule in GEMINI.md as well, and combine it with placement.

Tool settings are a safety net, not a wall

In all three tools, settings make secrets harder to read, not impossible. The reliable control is not having the secret in a readable place at all.

The real fix: keep secrets out of the repository

  • Commit a .env.example with variable names only, and point the AI at it.
  • Use a secrets manager (1Password CLI, AWS Secrets Manager, Doppler) that injects values at run time. A file that does not exist cannot be read.
  • direnv and environment variables: .envrc is read by the shell, not by the agent, unless it runs cat on it. Deny the env command anyway.
  • Clean Git history: secrets committed in the past are visible through git log -p. Revoke them, then remove them from history if needed.

MCP servers

Tokens passed to a server through env reach the server process, not the model directly. But whatever the server returns (API responses) does reach the model. Make sure no tool returns configuration that includes tokens, and never write tokens into configuration files; see Adding MCP servers to Claude Code.

CI and cloud runs

In GitHub Actions or Codex cloud, secrets and environment variables are available inside the container, and the agent can read them by running env.

  • Pass the agent only the variables it needs
  • Never give the CI agent production credentials; use test values
  • Do not register production values in cloud environment settings either

After a leak

Sent data cannot be recalled. Do this, in order:

  1. Revoke and reissue the key, token or password
  2. Check the service's logs for misuse between the leak and the revocation
  3. Find which setting was missing and fix the deny rule or the file placement
  4. If the secret was in Git history, remove it from history in addition to revoking it

Do not skip rotation because "only I saw it". How long the data is retained depends on your plan and contract.

Summary

  • .gitignore does not stop the agent from reading files; each tool needs its own exclusions
  • Claude Code: deny with Read(...); Codex: placement plus AGENTS.md; Gemini CLI: .geminiignore plus GEMINI.md
  • The real fix is keeping secrets out of readable locations: .env.example and a secrets manager
  • After a leak, revoking and reissuing is the only reliable remedy

FAQ

Are files listed in .gitignore hidden from the AI?
Not necessarily. .gitignore only controls what Git tracks; it does not stop an agent from reading a file. Each tool needs its own exclusion settings.
What should I do if the AI already read a secret?
Revoke and reissue the key or token. Data that has been sent cannot be recalled, so rotation is the only reliable remedy.
Can secrets leak through MCP servers?
Yes. Environment variables passed to a server, and anything the server returns, can reach the model. Pass tokens via environment variables and check that servers never return secrets in their output.

Primary sources

This article was drafted by AI from official documentation and reviewed by the site operator before publishing. Found a mistake? Let us know via the contact page.