OpenAI Codex Security CLI: What One Real Scan Costs

Last Updated: 2026-07-29 03:09:58

I pointed the new Codex Security CLI at a repository containing one file and nine lines of Express code. Eight and a half minutes later the scan halted against a $6.00 ceiling, having burned 7.0 million input tokens to produce a 1,605-word threat model and zero findings. That is the headline for anyone planning to wire this into CI: scan cost tracks the agent's reasoning loop, not your line count, so set --max-cost before you set anything else.

The tool is still worth understanding, because it is the first version of Codex Security you can run without handing your repository to a GitHub App.

OpenAI codex-security repository on GitHub showing Apache-2.0 license and 1.8k stars

What the CLI is, and what it is not

Codex Security itself is not new. OpenAI put it into research preview in March 2026 as a hosted service: you connect a GitHub repository, it builds a threat model, scans commit history in an isolated environment, and reports findings in a ChatGPT workspace. SecurityWeek reported availability for ChatGPT Pro, Enterprise, Business and Edu customers.

What landed on July 28, 2026 is different. openai/codex-security is an Apache-2.0 CLI and TypeScript SDK, published to npm as version 0.1.0 at 17:09 UTC with 0.1.1 following at 23:48 UTC the same day. At the time of writing it shows 1.8k stars and 28 open issues. This is a day-one project.

Installation needs Node.js 22 or later and Python 3.10 or later, because the scan engine ships as a bundled Python plugin:

npm install @openai/codex-security
npx codex-security info

info is the fastest way to see what you got:

sdkVersion: 0.1.1
bundledPluginVersion: 0.1.14
cliVersion: 0.1.1
codexVersion: 0.144.6
model: gpt-5.6-sol
reasoningEffort: xhigh

Those last two lines are the whole cost story. On this install, scans default to GPT-5.6 Sol at xhigh reasoning effort. --model overrides the choice, but the plugin is built around a deep agentic loop, and the loop is what you pay for.

The command surface is wider than the hosted product suggests: scan, validate, patch, scans (list, show, rerun, match, compare), bulk-scan, export to CSV, JSON or SARIF, install-hook, plus an mcp mode that registers the tool as an MCP server. Note that info also reports scanMcp: false, because scans cannot be cancelled over the MCP transport.

Two auth paths, and the one that will block you

npx codex-security login signs in with a ChatGPT account, --device-auth covers headless machines, and OPENAI_API_KEY covers CI. With a key and a sign-in both present, interactive scans ask which to use and non-interactive runs give the API key precedence.

One caveat in the official docs deserves reading twice: full-repository scans may additionally require Trusted Access for Cyber, and neither signing in nor setting an API key grants it. Plan for an access request, not a login.

Running the OpenAI Codex Security CLI against a compatible endpoint

Setting OPENAI_API_KEY to a third-party key and expecting it to route there is the first thing that fails:

codex-security: Authentication failed using OPENAI_API_KEY.

The key alone does not redirect anything, because the embedded Codex runtime still targets OpenAI's own base URL and ignores OPENAI_BASE_URL. Override the provider config through --codex, which takes TOML values:

OPENAI_API_KEY=sk-... npx codex-security scan . --auth api-key --max-cost 5 \
  --codex 'model_provider="relay"' \
  --codex 'model_providers.relay.name="relay"' \
  --codex 'model_providers.relay.base_url="https://your-endpoint/api/v1"' \
  --codex 'model_providers.relay.env_key="OPENAI_API_KEY"' \
  --codex 'model_providers.relay.wire_api="responses"'

Two details cost me a run each. Unquoted values fail with Invalid --codex TOML value. And wire_api="chat" is rejected outright by Codex 0.144.6, with an error pointing at discussion #7782 and telling you to use responses. Your endpoint has to implement the Responses API, not only Chat Completions.

Where the model bill lands follows from the same setting. The CLI always estimates in OpenAI list prices for GPT-5.6 Sol, whatever endpoint you point it at, so its running total is a token-count calculation rather than your invoice. Route the same traffic through an endpoint priced at half of list and the $6.03 run below costs you about $3, while the CLI keeps printing $6.03.

What one scan costs

Read the numbers below with one condition attached: all five runs went through third-party OpenAI-compatible endpoints, because I had no ChatGPT Business or Enterprise sign-in to test the official path. What follows measures the CLI as an ordinary developer can run it today, not the behaviour of the hosted service on an entitled account.

The test repository is deliberately small and deliberately broken. Nine lines, four planted flaws:

const express = require('express');
const { exec } = require('child_process');
const db = require('./db');
const app = express();
const API_KEY = "sk-live-9f3a2b7c1d4e5f6a8b9c0d1e2f3a4b5c";
app.get('/u', (req, res) => db.query("SELECT * FROM users WHERE id = " + req.query.id, (e, r) => res.json(r)));
app.get('/ping', (req, res) => exec("ping -c 1 " + req.query.host, (e, o) => res.send(o)));
app.get('/f', (req, res) => res.sendFile(__dirname + "/files/" + req.query.name));
app.listen(3000);

String-concatenated SQL, child_process.exec on a query parameter, an unsanitised sendFile path, a hard-coded key. Environment: macOS, Node v22.17.0, Python 3.14.6, @openai/[email protected], bundled plugin 0.1.14, all runs on 2026-07-29 between 02:20 and 03:05 UTC.

RunTargetBudgetHalted atElapsedCached inputFresh inputOutputFindings
1Full repo, standard mode$1.00$1.463m23s1,092,608121,39610,3000
2Full repo, standard mode$6.00$6.038m33s6,654,720331,33034,9460
3Working tree, one-line diff$3.00$3.069m46s2,035,712240,44828,1200
4Full repo, complete project$8.00$8.548m00s7,299,840634,41957,2230
5Full repo, reasoning_effort=low$3.00$3.204m13s1,749,248366,84116,2690

Those dollar figures are the CLI's own estimate, printed as the scan runs and stored in scans list. They are computed from token counts at OpenAI list prices, not from what an endpoint actually invoices, and cached input is the reason the totals look low against the token counts. Run 2 reconciles exactly at $5.00 per million fresh input, $0.50 per million cached input and $30.00 per million output:

331,330 x $5.00/M   = $1.657
6,654,720 x $0.50/M = $3.327
34,946 x $30.00/M   = $1.048
                      ------
                      $6.032   (CLI reported $6.03239)

The same three rates reproduce all five run totals to the cent, which is a useful sanity check if your own numbers ever look wrong.

Not one of the five finished. All stopped on budget, and scans list reports each as phase: preflight, status: failed with coverage: worklistRows 0, meaning no run reached the stage that reports vulnerabilities.

Run 4 is the control. My first repository was incomplete by design, with no package.json and ./db imported but absent, which the tool's own threat model flagged as an explicit unknown. Rebuilt properly at four files and thirteen lines, with declared dependencies, it cost more rather than less: $8.54 and 7.9M input tokens.

Estimated cost accrual over eight minutes of scanning a nine-line repository

The curve is not linear. Cost creeps for the first three minutes, then steps twice, and each step lines up with the agent widening its work. The log announces the mechanism once, at 51 seconds: Preflight: worker delegation supported (up to 8 worker slots).

Token breakdown showing 6.65M cached input tokens versus 0.33M fresh input and 35k output

95% of the input tokens were cache reads, which tells you the same context was re-sent turn after turn rather than newly read. Cheap per token, and still the largest line in the bill. Seven million tokens add up even at cached-input rates, against a nine-line file.

This is where the widely-repeated estimate of roughly $0.02 per 1,000 lines of code breaks down. At that rate my repository should have cost a fraction of a cent.

Turning reasoning down helps less than you would hope

Run 5 sets model_reasoning_effort="low" on the same project as run 4. Token consumption dropped from roughly 1.0M per minute to 0.5M per minute, so the same dollar buys twice the wall-clock time. It still hit its ceiling in the same preflight phase with nothing to report. Halving the burn rate does not help if the pipeline needs more turns than the budget covers either way.

--max-cost is a checkpoint, not a brake

Budget set versus cost when the scan halted, across five runs with caps from $1 to $8

The official CLI docs say requests already in progress can finish above the limit. They do not say by how much, and across five runs the overshoot ranged from 0.5% to 46%: the $1.00 cap halted at $1.46, the $6.00 cap at $6.03, and the three mid-range caps landed 2% to 7% over. Overshoot equals whatever the agent had in flight, so a worker fan-out landing near the ceiling is the expensive case. Set the ceiling below the number you cannot exceed.

The pre-commit path is not the cheap path

The obvious answer to a runaway full scan is to scan only what changed. I committed a clean baseline, added one vulnerable line, a LIKE clause built by string concatenation, and ran --working-tree --base HEAD.

It cost more than the first full scan: 9m46s, 2,276,160 input tokens, stopped at $3.06 against a $3.00 ceiling. It did get further down the pipeline than the full scans, writing a ranked review worklist (rank_input.jsonl, deep_review_input.jsonl) before the budget ran out, but it produced no findings either. Scoping to a diff does not shrink per-turn context: the agent still reads the repository, still writes a complete threat model, still fans out to workers.

install-hook wires this into a Git pre-commit hook that blocks high-severity findings and scan errors. Before installing that on a team, price a single diff scan on your own codebase, because it is a hook that can add minutes and dollars to each commit.

Where it still cannot help you

The threat model the tool wrote for nine lines is good work. It identifies all four trust boundaries, calls the missing ./db module an explicit unknown, and declines to credit Express with protections it cannot verify. It also states its own limit plainly: "Controls not present in the repository must not be assumed."

That is the structural constraint. Source code is the only input, so anything decided at deploy time stays invisible: CORS policy, debug mode left on, weak TLS, missing security headers, cache poisoning, and runtime authorisation across services. Object-level authorisation flaws in particular need authenticated requests from two real identities to confirm, which no reading of source can supply.

Language depth is reportedly uneven too. One practitioner write-up of the hosted service puts coverage strongest in Python, JavaScript, TypeScript, Go and Java, with Ruby, PHP and Kotlin behind. I only tested JavaScript, so treat that as secondhand.

Should you run it?

Install it today if you want the threat model. That is the one artifact I received on every run: a 1,605-word document mapping trust boundaries, listing attacker stories, and defining what critical, high, medium and low mean for this specific service. It is also useful input to whatever else you run, since --knowledge-base accepts your own architecture docs and the generated model is editable.

Wait if you need predictable spend or an actual findings list. Across five configurations I got neither, at $1.46 to $8.54 a run, on a repository you can read in ten seconds. The documented outputs further down the pipeline, findings.json, coverage.json and report.md, are ones I never reached. Whether an entitled ChatGPT Business account behaves differently is the open question these tests cannot answer.

Neither obvious cost lever worked here: diff scoping and lower reasoning effort both ended at the same wall. The one that did change the arithmetic is the model rate, because the estimate is computed from token counts at list price, so an endpoint at half of list halves the same run. Budget from measured runs rather than from repository size, and set the cap below your true limit by the size of one worker round: my worst overshoot was 46% of the cap.

FAQ

Is the Codex Security CLI free?

The CLI and SDK are Apache-2.0 and cost nothing to install. Scans are not free. They consume GPT-5.6 Sol tokens against whatever credential you authenticate with, and the CLI prints a running estimate at OpenAI list prices.

Do I need a ChatGPT Business or Enterprise plan?

For the hosted GitHub integration, yes: that path is limited to Pro, Enterprise, Business and Edu. The CLI accepts a plain OPENAI_API_KEY, but the docs warn that full-repository scans may still require Trusted Access for Cyber, which no plan grants automatically.

Can it run in CI?

Yes. Set OPENAI_API_KEY, add --fail-on-severity to turn findings into a non-zero exit code, and point CODEX_SECURITY_STATE_DIR at a writable path outside the repository. Scans are report-only by default.

Does it work with a third-party OpenAI-compatible endpoint?

It does, provided the endpoint implements the Responses API. You have to override the Codex provider config with --codex flags, because setting OPENAI_API_KEY alone fails authentication.

How is the CLI different from the Codex Security plugin?

Same scan engine, different entry point. The plugin runs in OpenAI's infrastructure against a connected GitHub repository. The CLI runs on your machine against a local path, keeps scan history in a local state directory, and adds diff-scoped scans, a pre-commit hook, SARIF export and an MCP registration.


Related reading: GPT-5.6 pricing guide · Codex auto mode