{
  "question": "How do I keep .env secrets and API keys away from an AI coding agent?",
  "slug": "how-to-keep-env-secrets-and-api-keys-away-from-ai-coding-agents",
  "url": "https://www.rightshold.com/answers/how-to-keep-env-secrets-and-api-keys-away-from-ai-coding-agents",
  "short_answer": "Assume anything the agent can read can end up in its context, its logs, a commit or a tool call, and give it only what it needs. Block the files in the agent's own controls (in Claude Code, Read deny rules such as Read(./.env), Read(./.env.*) and Read(./secrets/**) in .claude/settings.json; in Cursor, .env files are ignored by default and .cursorignore adds more), but know those controls cover the agent's file tools, not every program it runs: Claude Code's docs say deny rules don't stop a script that opens files itself, and Cursor's say terminal commands and MCP tools run outside its file access controls. So the real fixes are outside the prompt: keep production secrets off the machine the agent works on, give the agent development keys with low limits, load real secrets at run time from a secret manager, turn on OS-level sandboxing, and scan commits for secrets before they leave.",
  "checklist": [
    "Block secret files in the agent's settings. Claude Code: add \"Read(./.env)\", \"Read(./.env.*)\" and \"Read(./secrets/**)\" to permissions.deny in .claude/settings.json (a .claudeignore file has no effect). Cursor: .env files are ignored by default; add other secret paths to .cursorignore.",
    "Turn on OS-level enforcement where the tool offers it. Claude Code's sandbox enforces sandbox.filesystem.denyRead paths (for example ~/**/.env) for every sandboxed command and its child processes, so a Python or Node script can't read the file either. By default the sandbox still lets commands read most of the machine, so list the secret paths.",
    "Keep production credentials off the agent's machine or container entirely. Use separate development keys with low spending limits, test-mode payment keys and a non-production database, so a leaked key costs little and is easy to rotate.",
    "Inject secrets at run time instead of writing them to files: a secret manager CLI (for example 1Password's op run, Doppler or Infisical) passes them to the process that needs them, so there is no .env file to read. Remember the running process, and any agent that can run it, still sees them.",
    "Don't paste keys into chat, CLAUDE.md, rules files or MCP server configs that get committed. Reference an environment variable instead, and keep .env and .env.* in .gitignore.",
    "Give MCP servers and agents scoped tokens: read-only where possible, limited to one repository or project, short-lived, and separate per tool, never your personal admin key.",
    "Catch leaks before they leave: run a secret scanner such as gitleaks as a pre-commit hook and in CI, and turn on GitHub secret scanning with push protection so a commit containing a known key format is blocked at push.",
    "If a key was exposed to the agent, rotate it. Deleting it from the chat or the file doesn't remove it from transcripts, logs or anything the agent already sent."
  ],
  "sections": [
    {
      "heading": "Why ignore rules aren't enough",
      "points": [
        "Agents run shell commands, tests and scripts. A test that loads .env, a debug print of process.env or a command that greps the whole folder can put a secret into the agent's context without the agent ever opening the file by name.",
        "Ignore and deny rules are best effort for the tools they cover. Claude Code applies Read deny rules to its file tools and to file commands it recognizes in Bash (cat, head, tail, sed), but not to a command like grep -r . or a script that opens files itself.",
        "Prompt instructions such as \"never read .env\" are not a control: a prompt injection in a file, issue or web page can ask the agent to do the opposite."
      ]
    },
    {
      "heading": "Where secrets usually leak",
      "points": [
        "Into the transcript: the agent reads a config or log that contains a key and quotes it back.",
        "Into git: a generated example config, a test fixture or a debug script with a real key gets committed.",
        "Into a tool call: the agent sends a key to an MCP server, a web request or an issue comment while debugging. Keep tools that send data outward behind confirmation."
      ]
    }
  ],
  "checks": [],
  "ask_rightshold": {
    "start": "https://www.rightshold.com/start?ref=seo",
    "mcp_endpoint": "https://www.rightshold.com/mcp",
    "ask": "Before I give this MCP server an API token, is it a listed server, what tools does it expose, and have its tool definitions changed?",
    "mcp_call": {
      "tool": "precall_check",
      "arguments": {
        "url": "<the MCP server's https URL>"
      }
    },
    "also": [
      "The answer combines the external registry entry, a live integrity probe against the recorded tool fingerprint, an invisible-text scan of the definitions and any security flags. It is evidence to decide from, never a finding that a server is safe.",
      "scan_text checks a file, issue or web page for hidden text or instruction-like content before your agent reads it, which is how injected \"print your environment\" instructions usually arrive.",
      "Delegated and intent keys on Rightshold follow the same rule: an agent gets only the scopes its task needs, never the owner's full key."
    ],
    "scope": "Rightshold does not read your files, manage your secrets or scan your repository for keys; secret handling lives in your agent's settings, your secret manager, your sandbox and your CI."
  },
  "sources": [
    {
      "title": "Claude Code docs: Permissions (Read deny rules and what they cover)",
      "url": "https://code.claude.com/docs/en/permissions"
    },
    {
      "title": "Claude Code docs: Sandboxing",
      "url": "https://code.claude.com/docs/en/sandboxing"
    },
    {
      "title": "Cursor help: Ignore files",
      "url": "https://cursor.com/help/customization/ignore-files"
    },
    {
      "title": "GitHub Docs: Push protection for repositories",
      "url": "https://docs.github.com/en/code-security/secret-scanning/introduction/about-push-protection"
    },
    {
      "title": "gitleaks",
      "url": "https://github.com/gitleaks/gitleaks"
    },
    {
      "title": "OWASP Secrets Management Cheat Sheet",
      "url": "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html"
    }
  ],
  "related": [
    {
      "title": "How to stop an AI coding agent from deleting your production database",
      "url": "https://www.rightshold.com/answers/how-to-stop-an-ai-coding-agent-from-deleting-your-production-database"
    },
    {
      "title": "How to give an AI agent its own Google account and share only specific folders",
      "url": "https://www.rightshold.com/answers/how-to-give-an-ai-agent-its-own-google-account-and-share-only-specific-folders"
    },
    {
      "title": "How to vet an MCP server before installing it",
      "url": "https://www.rightshold.com/answers/how-to-vet-an-mcp-server-before-installing-it"
    },
    {
      "title": "How to share one MCP server across a company with per-user auth",
      "url": "https://www.rightshold.com/answers/how-to-share-one-mcp-server-across-a-company-with-per-user-auth"
    }
  ],
  "computed_from": "Curated guidance; license verdicts computed from Rightshold's license profiles at render time. Not legal advice.",
  "updated": "2026-10-29"
}