Keep API keys out of the commands Codex runs: the shell_environment_policy setting

Codex Published:

Control which environment variables reach the commands Codex CLI runs with shell_environment_policy: inherit values, default handling of KEY/SECRET/TOKEN names, filters, and set.

Verified on Sep 10, 2026 These tools change quickly. Please also check the latest official documentation.
Contents
  1. Default behavior
  2. The minimal configuration for keeping secrets out
  3. Fine-tuning with filters and set
  4. Relationship to the sandbox
  5. Summary

When Codex runs your tests or a build, how much of your shell environment does the command inherit? If AWS_SECRET_ACCESS_KEY or OPENAI_API_KEY is passed through, any command Codex generates can read it.

In short: [shell_environment_policy] in config.toml decides. Pick a base with inherit, drop variables whose names contain KEY, SECRET, or TOKEN with ignore_default_excludes = false, and fine-tune with filters and set.

KEY POINT

What you will learn

  • The three inherit values (all, core, none) and the default
  • How variables named with KEY, SECRET, or TOKEN are treated by default
  • Writing filters, set, and the legacy exclude / include_only, and the order they apply in

Default behavior

The official sample configuration documents the defaults in comments.

KeyDefaultMeaning
inherit"all"pass the whole shell environment
ignore_default_excludestrueskip the automatic exclusion of names containing KEY / SECRET / TOKEN (so they are not excluded)
set{}values to add or override explicitly
experimental_use_profilefalserun subprocesses via the user's shell profile (experimental)

So by default everything reaches the command, secrets included. The feature is often described as having automatic exclusions, but those exclusions are off unless you enable them.

用語解説

inherit values: all passes the shell environment as is, core passes what the docs call a trimmed set of essential variables, and none starts from an empty environment. With core and none, only values you add with set or allow with include patterns reach the command.

The minimal configuration for keeping secrets out

Enable the automatic exclusion. Names containing KEY, SECRET, or TOKEN then disappear from commands.

[shell_environment_policy]
inherit = "all"
ignore_default_excludes = false

Secrets whose names do not contain those words, such as a password embedded in DATABASE_URL, are not covered, so exclude them with filters.

Fine-tuning with filters and set

Write pattern-to-action pairs under [shell_environment_policy.filters]. Patterns are case-insensitive and support * and ?.

[shell_environment_policy]
inherit = "core"
ignore_default_excludes = false
set = { CI = "1", NODE_ENV = "test" }

[shell_environment_policy.filters]
"AWS_*" = "exclude"
"AZURE_*" = "exclude"
"DATABASE_URL" = "exclude"

The documented order of application:

  1. automatic exclusions (names with KEY / SECRET / TOKEN, when ignore_default_excludes = false)
  2. explicit exclusions such as filters
  3. set values
  4. include-pattern allowlists

A value added with set is still dropped if a later include pattern does not match it.

The legacy exclude = [...] and include_only = [...] arrays still work, but cannot be combined with [filters] in the same layer. For new configuration, use filters.

MCP server environments are separate

shell_environment_policy governs commands Codex runs in the shell. Variables for MCP servers are set separately with [mcp_servers.<id>.env] and env_vars. If a server needs a secret, scope it there as narrowly as possible.

Relationship to the sandbox

Restricting environment variables reduces what a command can read. Write access and network access are governed by other settings, sandbox_mode and sandbox_workspace_write. The overall picture is in the hub article Configuring Codex with config.toml and in Codex approval modes and sandbox settings. Secret handling in general is covered in Keeping secrets away from AI coding tools.

Summary

  • Defaults are inherit = "all" and ignore_default_excludes = true, so variables named with KEY / SECRET / TOKEN reach commands
  • ignore_default_excludes = false turns on the automatic exclusion of those names
  • Secrets not identifiable by name go under [shell_environment_policy.filters] as "pattern" = "exclude"
  • inherit = "core" or "none" plus set gives a pass-only-what-is-needed setup
  • Order: automatic exclusions, explicit exclusions, set, include allowlists. MCP server env is separate

FAQ

Do API keys reach Codex's commands by default?
According to the sample config, inherit defaults to all and ignore_default_excludes defaults to true, so by default everything is passed, including variables with KEY, SECRET, or TOKEN in the name. Set ignore_default_excludes = false to drop them.
Can I block variables by prefix?
Yes. Add patterns such as "AWS_*" = "exclude" under [shell_environment_policy.filters]. Patterns are case-insensitive and support * and ?.
How do I pass only the variables I choose?
Set inherit to core or none, then add values with set or allow specific names with include patterns.

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.