Codex Security Boundaries: Permissions, Sandboxes, and Secret-Leak Controls

"OpenAI Codex security documentation describes sandbox modes, approval policy, Cloud setup and agent phases, network proxy behavior, and the secrets lifecycle; this is the core source for the boundary model in this article."
Your project root has a .env file with a database password and third-party API keys. You open Codex and ask it to refactor some test code. The permission selector shows three choices: read-only, workspace-write, and danger-full-access. Which one should you choose?
After you pick workspace-write, Codex asks to run npm install. You approve it. Did you check whether the postinstall script in package.json can read environment variables or call a service you did not expect?
Then you move Codex into GitHub Actions for automated PR review. The workflow includes OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}. GitHub Secrets feels safe, but every test script, third-party action, and dependency lifecycle hook in that same job may be able to read that key.
Three boundaries answer these questions directly: instructions are not permissions, approvals are not isolation, and a sandbox is not an audit log. The rest of this guide is a minimum-permission checklist for local, Cloud, and CI Codex usage.
Permissions are not enforced by words: understand sandbox, approval, and permission profile boundaries
Many teams assume that writing “do not read .env” in AGENTS.md prevents Codex from accessing sensitive files. That is not permission control. It is project guidance. The actual security boundary comes from three layers: the sandbox constrains what spawned commands can touch, the approval policy decides when Codex has to stop and ask, and the permission profile is where access control is enforced.
Codex security is not one layer. The sandbox determines what git, package managers, test runners, and other spawned commands can access. Approval policy determines whether Codex must ask before sensitive actions. The permission profile is the layer where rules such as "**/*.env" = "deny" can actually be expressed. The three layers together are the practical permission model.
Sandbox modes: read-only, workspace-write, and danger-full-access
| Sandbox mode | Definition | Good fit | Risk |
|---|---|---|---|
read-only | Allows file reads only; no writes or command execution | Code review, architecture mapping, documentation drafting, read-only CI checks | It does not protect every secret on the runner; it still runs on that runner |
workspace-write | Allows writes inside the active workspace; command network access is off by default | Everyday local development, code changes, tests | Files under the workspace may still be readable, including .env, unless you add deny rules |
danger-full-access | Removes filesystem and network boundaries | Isolated CI runners, containers, fully controlled test environments | It may access ~/.ssh, /tmp, environment variables, and local services; do not use it as a daily default |
The sandbox constrains spawned commands, not just Codex built-in file operations. git, package managers, and test runners inherit the sandbox boundary. Platform prerequisites matter: Linux and WSL2 rely on bubblewrap or user namespaces, macOS relies on the system sandbox, and Windows support depends on the available platform mechanism.
Approval policy decides when Codex stops to ask:
| Approval policy | Definition | Common combination | Practical permission level |
|---|---|---|---|
on-request | Pause before selected actions and ask for approval | workspace-write + on-request for local automation | Lower risk; the user confirms writes, commands, and network requests |
never | Do not ask interactively; run directly | read-only + never for CI checks; danger-full-access + never only in controlled environments | Higher risk; workspace-write + never is especially risky without a permission profile |
Lower-risk combinations are read-only + never for CI-style read-only checks and workspace-write + on-request for local development. The high-risk combination is danger-full-access + never, and it belongs only in controlled environments.
Permission profile configuration: filesystem deny and network rules
A permission profile is enforced access control, not verbal guidance. Filesystem permissions support read, write, and deny. More specific rules override broader ones, and deny takes priority.
Example .env deny glob:
{
"filesystem": {
"rules": {
"**/*.env": "deny",
"**/.env.local": "deny",
"**/secrets/**": "deny",
"workspace/**": "write"
}
}
}
This makes .env files unreadable under workspace-write even when the broader workspace is writable. The specific deny rule wins over the broad write rule.
A network profile can set enabled = true and then apply domain allow and deny rules, with deny taking priority. Local and private networks are guarded by default; explicitly allowing localhost or a Docker socket is an exception. A Docker socket is a local escape hatch because it can reach local services, containers, and networks. Enable it only when the task truly needs it.
A network proxy constrains command network access after network access has been enabled. It does not grant network access by itself. A global * allow rule is broad network access and should be treated carefully.
Local minimum-permission checklist: from read-only review to full access
Local development is not safer just because permissions are broader. Approval prompts can catch some actions, but the sandbox and permission profile are the isolation layers. Start narrow, then widen only when the task requires it.
Permission decision table: when to use read-only and when to use workspace-write
| Scenario | Sandbox mode | Approval policy | Permission profile | Risk level |
|---|---|---|---|---|
| Code review or architecture mapping | read-only | never | No extra config needed | Low |
| Everyday development or code edits | workspace-write | on-request | Deny .env | Medium-low |
| Running tests or installing dependencies | workspace-write | on-request | Deny .env, review scripts | Medium |
| Read-only CI check | read-only | never | No extra config needed | Low |
| CI job that must write files | workspace-write | never | Add deny rules and use an isolated runner | Medium-high |
| Task truly needs full access | danger-full-access | never | Controlled environment only | High |
Steps for protecting .env and secret-bearing files:
- Identify the permission profile configuration used by your Codex setup.
- Add
"**/*.env" = "deny"to the filesystem permission rules. - Confirm that the more specific deny rule overrides broader rules.
- Test it by trying to read
.envinworkspace-write; access should be denied. - Extend the pattern with rules such as
"**/.env.local" = "deny"and"**/secrets/**" = "deny".
Do not rely on written guidance alone. AGENTS.md is guidance, not mandatory access control. Codex may follow it, but enforcement belongs in the permission profile.
Dependency install risk: npm postinstall, pip hooks, and Docker socket
Installing dependencies is not just downloading files. postinstall and prepare in npm or pnpm, and package hooks in pip install, can execute during installation. Those scripts may read environment variables, make network requests, or modify system-level files.
Risk checklist:
- Unknown postinstall scripts may read environment variables: even if
.envis denied, a lifecycle script runs in the spawned command environment and may still see environment variables. - They may make network requests: downloading extra binaries, reporting telemetry, or connecting to a private registry.
- They may modify system files: writing global config or changing
PATH.
Review recommendations:
- Review scripts and sources first: check the
scriptsfield inpackage.jsonand package setup hooks such assetup.py. - Use trusted sources: pin dependency versions and avoid accidental upgrades to unknown versions.
- Approve inside a controlled boundary: use
workspace-write + on-requestlocally, and approve only after Codex has shown what it wants to install.
A Docker socket is a local escape hatch. Allowing it is an explicit exception because it can reach local services, containers, and networks. Configure it only when the task needs it; do not leave it enabled by default.
Cloud boundaries: setup vs agent phase and the secrets lifecycle
A Cloud task does not run on your local machine. It runs in an isolated container managed by OpenAI. The sandbox constrains spawned commands, but secret safety mainly comes from the Cloud secrets lifecycle: secrets are available during setup and removed before the agent phase. The sandbox is not an audit system; security comes from layering.
Cloud container lifecycle:
- Create the container
- Check out the repo
- Run the setup script
- Apply network settings
- Let the agent run its command loop
- Return the answer or diff
setup vs agent phase: secrets are setup-only
| Phase | Network access | Secrets available | Environment variables | Dependency install |
|---|---|---|---|---|
| setup scripts | Available | Available | Present throughout | Dependencies can be installed |
| agent phase | Offline by default | Removed | Present throughout | Offline by default |
The setup phase can access the network, install dependencies, and read secrets. The agent phase is offline by default, secrets have been removed, and only environment variables remain.
Setup scripts run in a separate Bash session, so export does not automatically carry into the agent phase. If you run export MY_KEY=xxx in setup, the agent phase will not inherit it. Only Cloud secrets and environment settings are passed according to their lifecycle rules.
secrets vs environment variables: the important difference
| Type | Encrypted | Available phase | Use case | Lifecycle |
|---|---|---|---|---|
| environment variables | No extra encryption | setup + agent | Non-sensitive config, paths, switches | Present for the container lifecycle |
| secrets | Extra encryption | setup scripts only | Private repo access and dependency authentication | Removed before the agent phase |
Secrets are setup-only, which makes them a fit for dependency installation and private registry access. The agent phase should not need production secrets. Environment variables persist throughout the task and should be used only for non-sensitive configuration.
Dependency install boundary:
- The setup phase can install dependencies with network access.
- The agent phase is offline by default.
- Setup scripts can access secrets, so unknown scripts may leak them.
- Review scripts and sources first, use trusted sources, and avoid running unknown setup scripts with sensitive secrets.
Container cache can last up to 12 hours. Changes to setup, maintenance, env, or secrets can invalidate the cache.
CI and GitHub Actions: codex exec, API key mistakes, and official Action safety controls
codex exec defaults to a read-only sandbox, but many workflows still set OPENAI_API_KEY as a job-level environment variable. Test scripts, third-party actions, and dependency lifecycle hooks in that same job may all be able to read the key. The sandbox is not an audit system; minimum permission and key isolation matter more.
API key rule: do not use job-level env
Do not set OPENAI_API_KEY or CODEX_API_KEY as a job-level environment variable in a workflow that checks out or runs repository code. Repository code, tests, dependency lifecycle scripts, and third-party actions in that same job may still reach process environment variables.
Do-not list:
- Do not set
OPENAI_API_KEYas job-level env. - Do not set a job-level key in a workflow that checks out or runs repository code.
- Do not use
auth.jsonor ChatGPT-managed auth for public or open-source repo workflows. - Do not run untrusted code in the same process environment as the key.
Safer patterns:
- Single-invocation inline injection: set
CODEX_API_KEYonly for onecodex execinvocation.
- name: Run Codex
run: CODEX_API_KEY=${{ secrets.CODEX_API_KEY }} codex exec "review PR #${{ github.event.number }}"
- Official Action proxy: use the proxy provided by
openai/codex-action@v1.
- uses: openai/codex-action@v1
with:
prompt: "review PR #${{ github.event.number }}"
sandbox: read-only
safety-strategy: drop-sudo
In CI, danger-full-access only belongs in an isolated CI runner or container. Do not use it as the default because it can access runner-level resources.
GitHub Action safety checklist: restrict triggers, protect keys, rotate keys
Official Action parameters:
| Parameter | Default | Meaning |
|---|---|---|
safety-strategy | drop-sudo | Removes sudo privileges |
sandbox | - | Chooses read-only, workspace-write, or danger-full-access |
allow-users | Users with write access | Limits who can trigger the Action |
allow-bots | - | Controls whether bots may trigger it |
read-only does not mean every runner secret is protected. The Action still runs on the runner; it only constrains filesystem access. drop-sudo removes sudo privileges. sandbox should be the narrowest mode that can complete the task.
GitHub Action checklist:
- Restrict trigger users: use
allow-usersfor specific users, and enableallow-botsonly deliberately. - Sanitize PR, issue, and prompt input: treat untrusted text as prompt-injection input, not as a command.
- Protect API keys: do not use job-level env; use single-invocation inline injection or the proxy.
- Run Codex as the final step: reduce the time window in which the key exists.
- Rotate the key if leakage is suspected: stop the exposure before investigating.
Treat PR, issue, and prompt text as untrusted input. Do not pass raw PR comments or issue bodies directly into a Codex prompt without a boundary.
Secret leak response: the first step after a suspected leak
If a leak is suspected, the first step is not investigation. It is key rotation. Stop the exposure first, then audit. A sandbox can constrain spawned commands, but it cannot prevent Codex from outputting a key into logs, a PR comment, or an answer.
Secret leak response steps: rotate, audit, revoke
Step one: rotate the key. Do not wait for root-cause analysis before invalidating the old key.
Follow-up steps:
- Audit logs: check key usage records for abnormal calls.
- Revoke tokens: make sure the old key is fully invalid and there are no surviving sessions.
- Trace the source: inspect Codex logs, GitHub Action output, dependency install scripts, and third-party actions.
Prevention:
- Do not put API keys in frontend code or repositories.
- Do not set API keys as job-level env in CI.
- Use permission profile deny rules for
.env. - Rotate keys regularly, following OWASP Secrets Management Cheat Sheet guidance.
Codex Security boundary: it does not replace SAST or automatically apply patches
Codex Security is an LLM-driven security analysis toolkit that runs in an ephemeral isolated container and returns structured findings with patch suggestions. It can help discover and validate vulnerabilities, but it does not replace SAST or manual security review.
Limitations:
- It does not replace SAST.
- It does not replace manual security review.
- Proposed patches require user review and are not applied automatically.
- Its role is to assist discovery, validation, and remediation suggestions, not to approve fixes automatically.
Do not treat Codex Security as a universal security scanner. AI-driven analysis can catch some issues, but actual safety still comes from layered control: readable scope, writable scope, network access, secrets, approval, review, and revocation.
Conclusion
Codex security boundaries come from three layers: the sandbox constrains spawned commands, approval policy decides when Codex stops to ask, and the permission profile enforces access control. Together, those layers become practical permissions.
Remember three boundaries:
- Instructions are not permissions:
AGENTS.mdis guidance, not mandatory access control. Do not protect.envor API keys with words alone. - Approval is not isolation: approval policy can stop some actions, but the sandbox and permission profile provide the real isolation boundary.
- A sandbox is not an audit log: it constrains spawned commands, but it cannot prevent Codex from printing a key into logs, PR comments, or answers. Real safety comes from layering.
Quick self-check:
- Did you configure a
.envdeny glob? - Did you avoid job-level API keys in CI?
- Did you restrict who can trigger the GitHub Action?
- Did you review dependency install scripts?
- Do you have a key rotation plan?
Security boundaries do not catch logic errors. Codex may follow every permission rule and still generate buggy code, fail a test, or require rollback. Reviewing the diff, running tests, and preparing a rollback plan are the second line of defense beyond the permission boundary.
Suggested next reads:
- Failure review and verification workflow: understand how to handle Codex mistakes, validate diffs, and prepare rollback.
- codex exec automation and CI: go deeper into non-interactive CI workflows, workflow design, and error handling.
- AGENTS.md project rules: learn how to write project rules, while remembering that they are guidance, not a permission system.
Related reading:
- AI coding tools panorama 2026: understand the broader AI coding tool landscape.
- GitHub Actions CI basics: review CI workflow fundamentals.
- GitHub Actions deployment strategy: understand the boundary for secrets in deployment workflows.
- Frontend API key leak risks: why keys should not enter frontend code or repositories.
Set the smallest safe boundary for a Codex task
Choose sandbox, approval, permission, secrets, and CI job boundaries by task risk so write access, network access, dependency scripts, and API keys do not share one unbounded environment.
⏱️ Estimated time: 30 min
- 1
Step 1: Decide whether the task needs read, write, or network access
Use read-only for review and planning, workspace-write + on-request for code changes, and full access only inside an isolated runner or controlled container. - 2
Step 2: Move sensitive files out of scope or explicitly deny them
Add deny-read rules for .env, *.pem, credentials.json, and secrets directories. Do not rely on AGENTS.md wording alone. - 3
Step 3: Review scripts before approving dependency installs
Check package.json, postinstall, prepare, pip hooks, download scripts, and network targets before allowing install or network access. - 4
Step 4: Separate Cloud setup from the agent phase
Put private registry tokens and dependency credentials in Cloud secrets for setup scripts only. Keep only necessary non-sensitive env vars in the agent phase. - 5
Step 5: Split the Codex job from write-permission jobs in CI
Do not set API keys as job-level env. Keep the Codex job as read-only when possible, generate a patch artifact, and move comments, PR updates, or merges to later controlled jobs. - 6
Step 6: Review outputs and prepare key rotation
Inspect diffs, logs, artifacts, and test results. If a leak is suspected, rotate the key first, then audit the source.
FAQ
Is writing 'do not read .env' in AGENTS.md enough?
Can Codex read .env, ~/.ssh, or /tmp under workspace-write?
When is danger-full-access acceptable for Codex?
Can the Codex agent read Cloud secrets?
How should CI protect an API key when running codex exec?
Can Codex Security replace SAST or manual security review?
13 min read · Published on: Jul 26, 2026 · Modified on: Jul 27, 2026
OpenAI Codex: CLI, Desktop, Cloud, and Team Workflows
If you landed here from search, the fastest way to build context is to jump to the previous or next post in this same series.
Previous
Codex Automation Workflow: Use codex exec for Issues, Changelogs, and Documentation Checks
Use codex exec with stdin, JSONL, and schema output to build reviewable changelog, issue-triage, docs-drift, and Actions workflows with permission boundaries.
Part 7 of 10
Next
Codex Failure Cases: Why AI Breaks Code and How to Review Its Changes
A practical review workflow for Codex changes: spot oversized diffs, weak tests, CI shortcuts, missing review, and unclear scope, then use scope, plan, patch, verify, review, and rollback gates before merging.
Part 9 of 10



Comments
Sign in with GitHub to leave a comment