Codex Security Hardening skill for Codex

Least privilege for your coding agent. Codex audits its own effective configuration, applies a least-privilege baseline (workspace-write, on-request approvals, filtered environment, keyring credentials), denies secret files with a permission profile, routes network through a domain allowlist, leaves unfamiliar repos untrusted, and proves each control with an allowed and a blocked action.

  • Codex Mastery
  • $codex-security-hardening
  • 210 lines
  • 2 files
  • ~2,050 tokens
  • MIT
  • Updated
  • Editor's pick

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- codex-security-hardening

Installs to ~/.agents/skills/codex-security-hardening/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $codex-security-hardening, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Hardens a local Codex setup with least-privilege sandbox and approval settings, permission profiles that deny secret files, filtered shell environments, a domain-allowlisted network proxy, project trust for untrusted repos, execpolicy rules, MCP tool approval modes, keyring credential storage and safe CI key handling. Use when the user asks to lock down Codex, run it on an unfamiliar or untrusted repository, keep secrets away from the agent, review a teammate's risky config, or decide whether --yolo or danger-full-access is acceptable.

Use it when

  • Running Codex on an unfamiliar or untrusted repository
  • Keeping API keys, tokens and .env files away from the agent
  • Reviewing a config that uses danger-full-access, never or --yolo
  • Restricting network access to specific domains

Use something else when

How to check the result

From a hardened session, writing outside the workspace fails, env shows no token variables, an unlisted domain is blocked, and execpolicy check reports forbidden for destructive commands.

The mistake it prevents

Assuming secret-looking environment variables are filtered by default, when ignore_default_excludes defaults to true and passes them to every command.

~/.agents/skills/codex-security-hardening/SKILL.md

--- name: codex-security-hardening description: Hardens a local Codex setup with least-privilege sandbox and approval settings, permission profiles that deny secret files, filtered shell… license: MIT ---

A Codex setup is hardened when the agent can do the task and nothing more: writes stay in the workspace, secrets are neither readable nor in the command environment, network goes only to named hosts, untrusted repos cannot load their own config or hooks, and every widening of access is an explicit, reviewable choice.

Threat model in one table

ThreatPrimary control
Agent edits or deletes outside the projectworkspace-write sandbox (or :workspace permission profile)
Prompt injection from repo files, issues, web results, MCP outputApprovals on, network off or allowlisted, web_search = "cached"
Secret exfiltration via env varsshell_environment_policy filters
Secret exfiltration via files (.env, cloud creds)Permission profile deny rules, protected paths
Malicious repo config, hooks or rulesLeave the project untrusted
Destructive commands (rm -rf, force push, prod CLIs)execpolicy forbidden / prompt rules
Side-effecting MCP toolsdefault_tools_approval_mode, tool allowlists
Leaked Codex credentialsKeyring storage, inline-only API keys in CI

Workflow

- [ ] 1. Inspect the effective configuration
- [ ] 2. Apply the baseline
- [ ] 3. Lock down secrets
- [ ] 4. Constrain network and tools
- [ ] 5. Decide trust for each repository
- [ ] 6. Verify with deliberate allowed and blocked actions

1. Inspect

codex --version
codex doctor --summary             # install, config, auth and runtime health
codex features list                # effective feature flags

In a session, /status shows sandbox, approval policy and writable roots; /debug-config shows every config layer and any admin requirements. Check ~/.codex/config.toml, any ~/.codex/*.config.toml profile files and the repo’s .codex/config.toml.

2. Baseline (user config)

# ~/.codex/config.toml
sandbox_mode = "workspace-write"
approval_policy = "on-request"
allow_login_shell = false           # shell tools don't source login profiles
web_search = "cached"               # pre-indexed results, not live pages
cli_auth_credentials_store = "keyring"

[sandbox_workspace_write]
network_access = false              # default; opt in per task

[shell_environment_policy]
inherit = "core"
ignore_default_excludes = false     # default is true: KEY/SECRET/TOKEN vars pass through!

[shell_environment_policy.filters]
"AWS_*" = "exclude"
"GITHUB_TOKEN" = "exclude"
"NPM_TOKEN" = "exclude"
"*_API_KEY" = "exclude"

approval_policy = "untrusted" is retired and can stop Codex from starting; remove it. For the old “approve every command” behaviour, mark the project untrusted (step 5).

3. Secrets on disk

In workspace-write, .git, .agents, .codex and .aws inside writable roots are read-only, but readable. To make secret files unreadable, use a permission profile (beta; do not mix with sandbox_mode in the same setup, the older keys win):

default_permissions = "hardened"

[permissions.hardened]
extends = ":workspace"

[permissions.hardened.filesystem.":workspace_roots"]
"**/*.env" = "deny"
"**/*.pem" = "deny"
"config/credentials*" = "deny"

Keep real secrets out of the repo entirely; use a secret manager the agent cannot query.

4. Network and tools

Allow only the hosts a task needs, with enforcement through the network proxy:

[sandbox_workspace_write]
network_access = true

[features.network_proxy]
enabled = true
domains = { "registry.npmjs.org" = "allow", "**.github.com" = "allow" }

Without network_proxy, network_access = true means unrestricted egress, and domain rules do nothing. deny beats allow; local and private addresses stay blocked unless explicitly allowed. The proxy does not cover web search, MCP connections or model traffic.

MCP servers:

[mcp_servers.jira]
enabled_tools = ["get_issue", "search_issues"]
default_tools_approval_mode = "writes"     # prompt for any tool not marked read-only

Command rules decide what happens when Codex asks to run a command outside the sandbox (~/.codex/rules/default.rules, Starlark, experimental):

prefix_rule(pattern = ["git", "push", ["--force", "-f"]], decision = "forbidden",
            justification = "Never force-push; open a PR instead.")
prefix_rule(pattern = ["terraform", ["apply", "destroy"]], decision = "forbidden")
prefix_rule(pattern = ["kubectl", "delete"], decision = "prompt")

Test them: codex execpolicy check --pretty --rules ~/.codex/rules/default.rules -- git push -f origin main.

5. Repository trust

Untrusted projects skip project .codex/ layers: config, hooks and rules. Use that for any repo you did not write or review:

[projects."/Users/me/src/third-party-sdk"]
trust_level = "untrusted"      # commands need approval unless a rule allows them

Before trusting a repo, read its .codex/config.toml, .codex/hooks.json, .codex/rules/, AGENTS.md files and .agents/skills/: they shape what the agent is told and what runs automatically. Project config cannot change providers, base URLs, notify or otel, but it can change model, sandbox defaults and MCP servers.

For an untrusted repo, run read-only first:

codex --sandbox read-only --ask-for-approval on-request -C ~/src/third-party-sdk

6. Automation and CI

  • Never put OPENAI_API_KEY or CODEX_API_KEY in job-level env when the job runs repo code; set CODEX_API_KEY inline on the single codex exec command, or use the Codex GitHub Action, which proxies the key.
  • --dangerously-bypass-approvals-and-sandbox (--yolo) and danger-full-access are acceptable only inside a disposable container or VM that is itself the boundary, with no credentials beyond what the task needs. Inside such a container a malicious repo can still read everything in it, including Codex auth.
  • --dangerously-bypass-hook-trust only for automation that already vets hook sources.

Gotchas

  • ignore_default_excludes defaults to true, so variables named *KEY*, *SECRET*, *TOKEN* are passed to commands unless you set it to false or filter them.
  • set in shell_environment_policy runs after exclusions and can re-add a secret.
  • auth.json (file storage) holds live tokens; never commit or share it.
  • Rules match argument prefixes only: ["git", "push", ["--force", "-f"]] blocks git push -f origin main but not git push origin main -f. Keep the sandbox (no network, read-only .git) as the real boundary and treat rules as a second layer.
  • Approving a suggested prefix_rule in the TUI writes an allow rule to ~/.codex/rules/default.rules; review that file periodically.
  • web_search = "live" and --search fetch arbitrary pages: higher injection risk.
  • Docker without the capabilities bwrap needs breaks the Linux sandbox; fix the container rather than reaching for --yolo on a host.
  • Telemetry: keep [otel] log_user_prompt = false unless policy allows storing prompts.

Verification

Run each check and record the result:

codex exec --sandbox workspace-write "Run: touch ../outside.txt; report the error"    # expect denial
codex exec --sandbox workspace-write "Run: env | grep -ci token; report the number"   # expect 0
codex exec --sandbox workspace-write "Run: curl -sI https://example.com; report status" # expect blocked
codex execpolicy check --pretty --rules ~/.codex/rules/default.rules -- rm -rf /

Use codex sandbox to run one command directly under the sandbox (newer releases take a platform subcommand, e.g. codex sandbox macos --log-denials <cmd>; check codex sandbox --help).

Output template

## Codex hardening report
| Control | Before | After | Verified by |
|---|---|---|---|
| Sandbox / approvals | danger-full-access / never | workspace-write / on-request | touch ../outside.txt denied |
| Env secrets | 14 *_TOKEN vars passed | 0 | env grep count |
| Network | unrestricted | proxy, 2 domains | curl example.com blocked |
| Repo trust | trusted by default | third-party-sdk untrusted | /debug-config |
Remaining risks: <list>

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Codex Security Hardening"
  short_description: "Least privilege for your coding agent"
  default_prompt: "$codex-security-hardening Lock down my Codex config before I point it at this third-party repo"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
Just launched

Codex Skills Pro is live

79 premium skills for Codex, each with scripts, references and an evidence report that proves the result.

Bought one by one$882.21
All 79 skills$49
94% off

That's $0.62 a skill, paid once.

Get all 79 for $49Or pick single skills from $4.99 →

Secure checkout by Creem