Skip to content

A security audit with Codex runs deterministic scanners first, then parallel read-only codex exec audits, one per security domain, and merges their findings. Each accepted finding gets an exploit test that fails before the fix, and the fix runs in its own Git worktree. AGENTS.md review rules and a scheduled sweep stop the same classes from returning.

A security researcher has filed a responsible disclosure: your API returns stack traces in production error responses, and the password reset endpoint tells an attacker which email addresses have accounts. The report goes public in 48 hours. You need to fix those two, find every sibling of them in the codebase, and make sure the next pull request cannot reintroduce them. This page is for the developer who runs that audit with Codex and the tech lead who owns the gates afterwards.

What you’ll walk away with from a Codex security audit

Section titled “What you’ll walk away with from a Codex security audit”
  • A seven-step audit order, from containing live secrets to scheduling the next sweep.
  • A shell loop that runs three domain audits in parallel under the :read-only permission profile, so no audit can edit what it judges.
  • Six copy-paste prompts: targeted investigation, three domain audits, a merge-and-dedupe pass, and an exploit-test-first fix.
  • A rule for accepting fixes without reading every diff line: no failing exploit test, no fix.
  • A security block for the ## Code Review Rules section of AGENTS.md, with “Do not flag” lines that keep the noise down.

This page covers the hands-on audit you drive from the Codex CLI. OpenAI’s Codex Security agent, @codex security review and the finding-to-merge lifecycle are covered in Codex Security and the agents command center; the CI gate built on openai/codex-action is in Codex in CI/CD.

Which Codex tool fits which part of the audit?

Section titled “Which Codex tool fits which part of the audit?”

Each part of an audit needs a different level of access. Checked against Codex CLI 0.157.1 on 2026-09-26, except the two GitHub surfaces, which were last verified on OpenAI’s docs on 2026-08-28.

Part of the auditToolAccess it needsWhat you get
Secrets, known-vulnerable packages, rule-based patternsGitleaks, TruffleHog, npm audit, Semgrep (not Codex)Your shell and the networkDeterministic reports Codex can reason over
Investigating a reported issue or one security domaincodex exec with -c 'default_permissions=":read-only"'Read the repository, no writes, no networkA findings report per domain
Confirming a finding and fixing itcodex --worktree with the :workspace profileWrite inside an isolated checkoutA failing exploit test, then a fix on a branch
Checking a branch before it becomes a pull requestcodex exec review or /reviewRead the diffReview findings steered by AGENTS.md
Checking a pull request@codex security review on GitHubCodex’s GitHub connectionSecurity-focused review comments
Repeating the sweepA Codex desktop app automation, or codex exec from cronSame as the domain auditA daily report of new findings only

The default model in Codex is GPT-6.1 Sol, which runs at low effort unless you change it (see the models hub). An audit traces input across many files, so raise effort for the audit runs with -c model_reasoning_effort="high" before you consider a different model.

How to run a Codex security audit, step by step

Section titled “How to run a Codex security audit, step by step”

The order matters. Containment comes first, because a leaked key is being abused while you read the report. Scanners come before Codex, because their output is ground truth the agent can reason over, and the read-only profile gives Codex no network to run them itself.

  1. Contain live secrets and give Codex a clean copy. Run the audit in a fresh clone of the repository. A fresh clone has no gitignored .env, so the audit sessions do not read the credentials in your local .env; committed secrets are what step 2 finds. To audit code you do not trust, such as a vendor’s repository, choose Open restricted at Codex’s “Trust this folder?” prompt: config, hooks and exec policies from an untrusted folder stay disabled, and since Codex 0.150.0 an untrusted project does not supply its AGENTS.md either.

    Terminal window
    git clone --no-local . ../app-audit && cd ../app-audit
  2. Run the deterministic scanners and keep their output. Install the scanners first, for example brew install gitleaks trufflehog semgrep jq (or pip install semgrep). You need Gitleaks 8.19.0 or later: that release added the git subcommand, and older versions only know detect (checked against the Gitleaks releases on 2026-09-26). Then, in a terminal at the root of the audit clone:

    Terminal window
    mkdir -p audit
    gitleaks git --redact --report-path audit/gitleaks.json # secrets in full git history, values masked
    trufflehog git file://. --results=verified,unknown --json \
    | jq -c 'del(.Raw, .RawV2)' > audit/trufflehog.json # live check against the issuing service; raw values stripped
    npm audit --omit=dev --json > audit/npm-audit.json # advisories in production dependencies
    semgrep scan --config auto --json -o audit/semgrep.json # rule-based patterns; auto sends your project URL to the Semgrep Registry

    Both reports keep the raw secret by default. --redact masks it in the Gitleaks report, and the jq filter drops the Raw and RawV2 fields from each TruffleHog result, because Codex reads these files in step 4 and anything it reads goes to the model provider. The commit, file and detector name are still there, which is all the audit needs.

    Any secret TruffleHog reports as verified is live. Rotate it now, before anything else on this page. Codex cannot revoke a credential, and a secret that reached a pushed commit stays compromised after a history rewrite, because forks, clones and CI caches keep copies.

  3. Investigate the reported issues first, read-only. Paste the first prompt below into codex -c 'default_permissions=":read-only"'. It maps the reported vulnerabilities to code and proposes fixes without applying them, so you have a written plan for the disclosure deadline within the first hour.

  4. Run the domain audits in parallel. Save the three domain prompts below as .codex/audit/input-validation.md, .codex/audit/authz.md and .codex/audit/deps-config.md, then start all three at once:

    Terminal window
    for domain in input-validation authz deps-config; do
    codex exec \
    -c 'default_permissions=":read-only"' \
    -c model_reasoning_effort="high" \
    -o "audit/$domain.md" - < ".codex/audit/$domain.md" > "audit/$domain.log" 2>&1 &
    done
    wait

    Read-only audits do not need worktrees: none of them writes to the checkout, so all three can share it. codex exec has no -a in 0.157.1 and needs none: it runs with approval never, so a command that needs more access fails instead of waiting for an approval nobody is there to give. -o writes each session’s final report to a file, and - reads the prompt from standard input.

  5. Merge the reports into one list. Run the consolidation prompt below. Three audits find overlapping issues from different angles, and a single list with one ID per finding is what you triage, assign and close.

  6. Confirm each finding with a failing test, then fix it in a worktree. For every critical or high finding, start an isolated session with codex --worktree -c 'default_permissions=":workspace"' and paste the exploit-test-first prompt. Each finding gets its own worktree and branch, so fixes land as separate, reviewable pull requests. The Codex worktrees guide covers bootstrapping a worktree so the test suite runs in it.

  7. Lock the gates. Add the AGENTS.md rules below, run codex exec review before every push that touches a risky path, request @codex security review on pull requests (setup in code review with Codex), add the structured security gate from Codex in CI/CD, and schedule the daily sweep.

Copy-paste prompts for a Codex security audit

Section titled “Copy-paste prompts for a Codex security audit”

Every prompt tells Codex to treat repository content as data. OWASP’s GenAI LLM Top 10 2026 (GenAI Security Project, published 2026-08-04) lists “a public GitHub issue, a support ticket, or a malicious npm package” among the places attackers plant instructions for agents, and an audit reads all of them.

Save the merge prompt as .codex/audit/merge.md and run it with the :workspace profile, not :read-only, because it writes audit/findings.md:

Terminal window
codex exec -c 'default_permissions=":workspace"' - < .codex/audit/merge.md

Keep audit/ out of Git by adding it to .git/info/exclude in the audit clone: the reports describe exploitable paths in your code.

How do you verify security fixes without reading every line?

Section titled “How do you verify security fixes without reading every line?”

An audit is only useful if you can accept its output on evidence. These checks replace line-by-line review of each fix.

EvidenceWhat it provesWho signs off
Exploit test in tests/security/ that failed before the fix and passes afterThe finding was real and is closedThe security owner for that path, not the fix author
Full test suite and type check green on the fix branchThe fix did not change legitimate behaviourCI, as required checks
Scanners rerun clean: Gitleaks, and npm audit --audit-level=high exits zeroNo secret left in HEAD, no high advisory left unpatchedCI
The domain audit rerun on the fixed branch no longer reports the findingThe class is gone, not only the one instanceDeveloper who ran the audit
Every “Do not flag” line in AGENTS.md has a written reasonA false positive was judged, not ignoredTech lead

A human still reads two short things: the exploit test (does it attack what the finding describes?) and every suppression. The fix itself is judged by the test, the suite and the rescan. The finding-state table and sign-off rules for a team are in Codex Security and the agents command center.

To check the auditor itself, plant known defects once a quarter: a throwaway branch with string-built SQL, a route without an ownership check and a hard-coded token. Run the three domain audits against it. The number of planted defects they report is your baseline, and a drop after you change a prompt or the AGENTS.md rules is a regression.

Local reviews (/review, codex exec review) read the applicable AGENTS.md files (Codex 0.157.1); GitHub reviews look for the ## Code Review Rules section (OpenAI docs, checked 2026-10-12; the 2026-08-28 check named it ## Review guidelines). Put the rules under that heading and one rule serves both. The AGENTS.md guide covers where the file loads. Turn the findings from this audit into rules a reviewer can check from a diff:

## Code Review Rules
### Security
- P0: an error handler that returns err.stack, err.message from an internal error,
file paths or SQL text to the client. Log them; return { error: "internal" }.
- P0: SQL or NoSQL queries built with template literals or + concatenation.
- P0: a route under src/routes/ that loads a record by an ID from the request without
requireOwnership() or requireRole().
- P0: a secret, token or private key literal in any file, including tests.
- P1: auth endpoints (login, register, reset-password) without the rate limiter, or
with responses that differ for known and unknown accounts.
- P1: a new dependency that is not already in package.json; check that the name
exists on the registry and is the package the author meant.
- Do not flag: Drizzle .where() calls with bound values; they are parameterized.
- Do not flag: fake credentials under tests/fixtures/.
- When you report a finding, name the rule above that it violates.

The dependency rule is there because OWASP’s LLM04 Supply Chain entry (GenAI LLM Top 10 2026) warns that coding assistants “hallucinate plausible but nonexistent package names”, which attackers register in advance, a practice it calls “slopsquatting”.

Before each push that touches src/routes/, src/middleware/ or src/auth/, run a review against the base branch:

Terminal window
codex exec review --base main -o review.md

In Codex 0.157.1, --base, --uncommitted and --commit cannot be combined with custom review instructions: codex exec review --base main "focus on security" fails with the argument '--base <BRANCH>' cannot be used with '[PROMPT]'. That is why the security rules belong in AGENTS.md, where the preset review modes read them, rather than in a prompt.

A one-off audit decays as soon as the next pull request merges. A daily sweep reports only what changed. Run it as an automation in the Codex desktop app, or from cron on an always-on host with the same codex exec -c 'default_permissions=":read-only"' command as the domain audits. The Codex automations guide covers where a scheduled job should run and how to test the prompt before you schedule it; scheduled security scans covers retaining the evidence.

Regenerate audit/npm-audit.json in the job before Codex runs, since the read-only profile has no network. The exact “nothing new” line lets a script or a reader tell a clean run from a failed one at a glance.

The domain audits stop with permission errors. Under :read-only, commands that write or reach the network fail, and codex exec, which runs with approval never, returns the failure instead of asking. Recovery: run the command yourself (a scanner, a dependency install) and point the prompt at its output file. Do not switch the audit to :workspace or bypass the sandbox to get past it.

codex exec review rejects your security instructions. In 0.157.1 the --base, --uncommitted and --commit modes take no prompt. Recovery: move the instructions into the ## Code Review Rules section of AGENTS.md, or run codex exec with a prompt that names the diff (“review the changes on this branch against origin/main”).

Codex flags parameterized queries as SQL injection. It does not know your ORM binds values. Recovery: add a “Do not flag” line naming the ORM call, as in the AGENTS.md block above, and keep the rule that forbids template-literal SQL.

Two runs of the same audit report different findings. Model-based audits are nondeterministic. Recovery: treat the merged audit/findings.md as the record, rerun only the domain whose result you doubt, and let the planted-defect branch tell you whether a prompt change helped.

A finding is “confirmed” by argument, with no test. The session writes a convincing explanation instead of a failing test. Recovery: send it back with “write the failing test first; no explanation without it”, and do not open a pull request for that finding until the test exists.

A dependency upgrade breaks the build. The fixed version has breaking changes. Recovery: read the breaking-changes list from item 1b of the deps-config.md audit before upgrading, upgrade one package per commit, and leave NOT REACHABLE advisories on a tracked backlog instead of this week’s work.

The daily sweep repeats the same accepted findings. Every report lists the same medium advisories you triaged last month, and the team stops reading it. Recovery: record each accepted advisory ID with a reason and an expiry date in .security-ignore.json, and keep the prompt’s “only report IDs not in the ignore file” rule.

An audited repository runs its own hooks. Trusting a vendor’s repository to audit it enables its config, hooks and exec policies. Recovery: audit untrusted code in its own clone and choose Open restricted. A session that ran while the folder was trusted can keep that configuration, so start a new session after changing trust.

How do Claude Code and Cursor handle the same audit?

Section titled “How do Claude Code and Cursor handle the same audit?”

This page stays on Codex. Claude Code has /security-review and the Claude Security plugin, covered in security audits with Claude Code. Cursor’s security review features are covered in security in Cursor. The tool-neutral version of this workflow, with scanners as CI gates and any of the three agents triaging their output, is security operations automation.

Where to go next after a Codex security audit

Section titled “Where to go next after a Codex security audit”

Back to the Codex Operate overview.