Keep API keys out of the commands Codex runs: the shell_environment_policy setting
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.
Contents
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
inheritvalues (all,core,none) and the default - How variables named with KEY, SECRET, or TOKEN are treated by default
- Writing
filters,set, and the legacyexclude/include_only, and the order they apply in
Default behavior
The official sample configuration documents the defaults in comments.
| Key | Default | Meaning |
|---|---|---|
inherit | "all" | pass the whole shell environment |
ignore_default_excludes | true | skip the automatic exclusion of names containing KEY / SECRET / TOKEN (so they are not excluded) |
set | {} | values to add or override explicitly |
experimental_use_profile | false | run 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:
- automatic exclusions (names with KEY / SECRET / TOKEN, when
ignore_default_excludes = false) - explicit exclusions such as
filters setvalues- 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"andignore_default_excludes = true, so variables named with KEY / SECRET / TOKEN reach commands ignore_default_excludes = falseturns 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"plussetgives 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.