Read the codex-security README hunting for detection claims and you will come up empty. No rule count, no CWE coverage table, no accuracy figure, no list of languages it understands. What fills the page instead is bookkeeping: how a finding keeps its identity across scans, which credential ran the scan, where a report is allowed to travel, and what the tool declines to assert when it did not look hard enough. For a scanner whose engine is a language model, that emphasis is the correct one.
A finding is a claim, not a fact
scans compare BEFORE_SCAN_ID AFTER_SCAN_ID matches findings by root cause, reuses saved matches, and sorts each one into new, persisting, reopened, resolved, or unknown. That fifth bucket is where the design shows. Missing findings stay unknown when coverage was incomplete or the original location was not reviewed. A sloppier tool would mark anything that stopped appearing as resolved. This one refuses, because a nondeterministic scanner that skipped a file produces exactly the same silence as a real fix.
findings list [repository] applies the same rule from the other direction. It shows open findings across a repository's scans and calls out the ones the latest scan did not confirm, rather than letting them fall off the board. Anyone who has watched a security dashboard turn green because a job died halfway through will recognize why that distinction is worth a command.
Deep mode inherits the same posture toward its own limits. Discovery stops after 96 hours by default, --max-time-hours takes any positive number of hours up to that ceiling including fractions, and findings completed before the cutoff are preserved and returned. The scan is a budgeted search that ran out of budget, and the CLI is willing to say so.
It treats its own output as hazardous material
--verbose prints scan diagnostics to stderr, and the README immediately warns that those diagnostics may contain sensitive data and that you should review local logs before sharing them. Saved failure summaries, bulk-scan receipts, and the normal activity feed omit messages containing recognizable credentials. Press d during a scan and you get unredacted details, with the plain caveat that those events can contain credentials. The redaction is a default, not a guarantee, and the interactive escape hatch is labeled as such.
Credential handling follows the same pattern of narrowing rather than promising. Environment API keys are passed directly to the current scan and never written to Codex's credential home or system keyring. Local sign-in honors whatever credential backend Codex is configured with, including a system keyring on a managed device. When both a ChatGPT sign-in and an API key are present, an interactive scan asks which to use while CI and other noninteractive runs keep the existing API-key precedence, so automation behavior does not shift under you. --auth chatgpt and --auth api-key settle it explicitly.
Scan history lands in the Codex Security workbench state directory, and CODEX_SECURITY_STATE_DIR moves it somewhere writable outside the repository. Worth doing deliberately. A scan history is a catalog of your code's weak points, and it should not end up in a commit.
Publishing is the widest blast radius
The Linear integration is the part I would put through review before anyone runs it. publish scan creates a new issue for every finding, and each issue carries the scan ID, affected code locations, source snippets, and remediation guidance. The README's own instruction is to choose a destination authorized to receive the repository's source code and vulnerability details. That is an accurate description of what you are about to mail into a project tracker. --dry-run previews the issues first.
Two authorization paths exist. The default rides your existing Codex sign-in and connected Linear app with no separate token. Setting CODEX_SECURITY_LINEAR_API_KEY switches to direct publication through the Linear API, which leaves issues unassigned unless you pass --linear-assignee. The --linear-api-key flag also selects direct publication and beats the environment variable, though the README tells you to prefer the variable so keys stay out of shell history and process listings.
Fixes are opt-in and resumable
Ordinary scans do not change repository files. Patching is a separate verb: --patch --patch-severity high covers high and critical, --create-pr commits the verified files and opens a GitHub pull request, and each selected finding runs in its own saved Codex desktop task. If publication fails after the work is done, the printed patch --resume-pr BRANCH command retries without running Codex again, which is the right seam given that inference is the expensive half.
Judge this tool the way its own commands suggest. Not by what a single scan reports, but by which findings survive the next comparison.
GitHub: https://github.com/openai/codex-security
Curated by Agent Palisade — practical AI for small and mid-sized businesses.
Top comments (0)