SpyBara
Go Premium

Documentation 2026-08-07 18:59 UTC to 2026-08-08 03:02 UTC

6 files changed +327 −101. View all changes and history on the product overview
2026
Mon 31 19:59 Sat 29 07:02 Fri 28 23:02 Thu 27 21:01 Wed 26 23:58 Tue 25 19:59 Mon 24 22:00 Fri 21 19:59 Thu 20 23:59 Wed 19 22:57 Tue 18 13:01 Mon 17 23:58 Sat 15 01:01 Fri 14 22:00 Thu 13 22:59 Wed 12 19:59 Tue 11 22:59 Mon 10 22:00 Sat 8 03:02 Fri 7 18:59 Thu 6 23:58 Wed 5 19:00 Tue 4 22:00 Mon 3 23:00 Sun 2 21:00

security/cli.md +55 −23

Details

14 14 

15## Check the prerequisites15## Check the prerequisites

16 16 

17The CLI requires Node.js 22 or later. Running a scan or exporting findings also17The CLI requires Node.js 22.13.0 or later. Running a scan or exporting findings

18requires Python 3.10 or later. For more detail, see [Authentication and18also requires Python 3.10 or later. For more detail, see [Authentication and

19prerequisites](https://learn.chatgpt.com/docs/security/cli/reference#authentication-and-prerequisites).19prerequisites](https://learn.chatgpt.com/docs/security/cli/reference#authentication-and-prerequisites).

20 20 

21## Set up and verify the CLI21## Set up and verify the CLI


55```55```

56 56 

57For AWS credentials, see [Amazon Bedrock57For AWS credentials, see [Amazon Bedrock

58setup](https://learn.chatgpt.com/docs/security/cli/reference#use-amazon-bedrock).58setup](https://learn.chatgpt.com/docs/security/cli/reference#use-amazon-bedrock). For [OpenRouter or

59Fireworks](https://learn.chatgpt.com/docs/security/cli/reference#use-openrouter-or-fireworks), set the

60provider's API key and select a model with `--provider` and `--model`.

59 61 

60To use your ChatGPT sign-in when an API key is also set, select it explicitly:62To use your ChatGPT sign-in when an API key is also set, select it explicitly:

61 63 


98npx @openai/codex-security scan "$REPOSITORY" --output-dir "$SCAN_DIR" --dry-run100npx @openai/codex-security scan "$REPOSITORY" --output-dir "$SCAN_DIR" --dry-run

99```101```

100 102 

101The dry run checks local inputs without starting Codex, loading credentials,103The dry run checks local inputs, including any `--knowledge-base` paths,

102or probing the plugin's Python interpreter.104without starting Codex, loading credentials, or probing the plugin's Python

105interpreter.

103 106 

104## Run your first scan107## Run your first scan

105 108 


109npx @openai/codex-security scan "$REPOSITORY" --output-dir "$SCAN_DIR"112npx @openai/codex-security scan "$REPOSITORY" --output-dir "$SCAN_DIR"

110```113```

111 114 

115Interactive terminals show a live scan dashboard. Add `--headless` to show

116plain progress lines instead. CI and terminals without an interactive session

117use plain progress automatically.

118 

112By default, the CLI writes scan progress and its completion summary to stderr.119By default, the CLI writes scan progress and its completion summary to stderr.

113It doesn't print the full scan result to stdout. A completed scan prints a120It doesn't print the full scan result to stdout. A completed scan prints a

114summary like this:121summary like this:


203npx @openai/codex-security scan "$REPOSITORY" --mode deep210npx @openai/codex-security scan "$REPOSITORY" --mode deep

204```211```

205 212 

206Deep mode supports repository and path targets, not diff or working-tree scans.213To control discovery workers, subagents, and when the scan stops:

214 

215```bash

216npx @openai/codex-security scan "$REPOSITORY" \

217 --mode deep \

218 --workers 2 \

219 --subagents 0 \

220 --stop-after-no-new 3 \

221 --max-discovery-runs 10

222```

223 

224These options require deep mode, which supports repository and path targets,

225not diff or working-tree scans. Here, `--workers` controls discovery workers

226within one scan; `bulk-scan --workers` controls concurrent repository scans.

207 227 

208## Add architecture and security context228## Add architecture and security context

209 229 


217 --knowledge-base /path/to/security-policies237 --knowledge-base /path/to/security-policies

218```238```

219 239 

240## Add custom scan instructions

241 

242Add instructions that focus the scan on your security priorities. Use a

243second file for a follow-up after a validated scan with complete coverage:

244 

245```bash

246npx @openai/codex-security scan "$REPOSITORY" \

247 --scan-prompt-file /path/to/scan.md \

248 --post-scan-prompt-file /path/to/follow-up.md

249```

250 

251The follow-up runs in the same authenticated session. Both options also work

252with `bulk-scan`; a CSV `prompt` column adds repository-specific instructions.

253 

220## Set a scan budget254## Set a scan budget

221 255 

222Use `--max-cost` to stop a scan when its estimated model cost exceeds a limit256Use `--max-cost` to stop a scan when its estimated model cost exceeds a limit


226npx @openai/codex-security scan "$REPOSITORY" --max-cost 5260npx @openai/codex-security scan "$REPOSITORY" --max-cost 5

227```261```

228 262 

229Requests already in progress can finish above the limit. Codex Security keeps263Requests already in progress can finish slightly above the limit. If a scan

230the available results when a scan stops.264aborts due to the cost limit, partial scan results remain available on disk.

231 265 

232## Scan changes before each commit266## Scan changes before each commit

233 267 


266 --workers 4300 --workers 4

267```301```

268 302 

269Run the same command again to resume an existing bulk scan. Completed303Run the same command again to resume an existing bulk scan. Codex Security

270repositories with intact result artifacts aren't scanned again. Add304skips completed repositories. Add `--max-attempts 3` when you want to retry

271`--max-attempts 3` when you want to retry temporary repository or scan errors.305temporary repository or scan errors.

272 306 

273For GitHub discovery, CSV preparation, campaign results, and Docker setup, see307For GitHub discovery, CSV preparation, campaign results, and Docker setup, see

274[Run bulk security scans](https://learn.chatgpt.com/docs/security/cli/bulk-scans).308[Run bulk security scans](https://learn.chatgpt.com/docs/security/cli/bulk-scans).


288 --workers 4322 --workers 4

289```323```

290 324 

291The container runs bulk scans without prompts. Use the CLI outside Docker when325The container runs bulk scans without interactive prompts. Use the CLI outside

292you want to discover repositories interactively. For private repositories,326Docker when you want to discover repositories interactively. For private

293provide `GH_TOKEN` or `GITHUB_TOKEN` through your environment or secret327repositories, provide `GH_TOKEN` or `GITHUB_TOKEN` through your environment or

294manager. The [sign-in requirements](#sign-in), including account and repository328secret manager. The [sign-in requirements](#sign-in), including account and

295access, also apply to containerized scans.329repository access, also apply to containerized scans.

296 330 

297## Revisit a saved scan331## Revisit a saved scan

298 332 


324npx @openai/codex-security scans rerun SCAN_ID358npx @openai/codex-security scans rerun SCAN_ID

325```359```

326 360 

327To compare two scans, first match findings that share the same root cause:361Compare two scans to find new, persisting, reopened, resolved, or unknown

328 362findings:

329```bash

330npx @openai/codex-security scans match PREVIOUS_SCAN_ID CURRENT_SCAN_ID

331```

332 

333Then check which findings are new, persisting, reopened, resolved, or unknown:

334 363 

335```bash364```bash

336npx @openai/codex-security scans compare PREVIOUS_SCAN_ID CURRENT_SCAN_ID365npx @openai/codex-security scans compare PREVIOUS_SCAN_ID CURRENT_SCAN_ID

337```366```

338 367 

368The comparison automatically matches findings by root cause and reuses saved

369matches.

370 

339For the bulk-scan CSV format, scan-history filters, and command options, see371For the bulk-scan CSV format, scan-history filters, and command options, see

340the [CLI reference](https://learn.chatgpt.com/docs/security/cli/reference).372the [CLI reference](https://learn.chatgpt.com/docs/security/cli/reference).

341 373 

Details

68Create a CSV with one row for each repository and pinned revision:68Create a CSV with one row for each repository and pinned revision:

69 69 

70```csv70```csv

71id,repository,revision,scope,mode71id,repository,revision,scope,mode,prompt

72payments,https://github.com/example/payments.git,0123456789abcdef0123456789abcdef01234567,services/api,standard72payments,https://github.com/example/payments.git,0123456789abcdef0123456789abcdef01234567,services/api,standard,Review payment authorization and refunds.

73identity,https://github.com/example/identity.git,fedcba9876543210fedcba9876543210fedcba98,,deep73identity,https://github.com/example/identity.git,fedcba9876543210fedcba9876543210fedcba98,,deep,Review session and identity boundaries.

74```74```

75 75 

76The CSV supports these columns:76The CSV supports these columns:


82| `revision` | Yes | Full 40- or 64-character Git commit SHA. Branch names, tags, and shortened commit hashes aren't supported. |82| `revision` | Yes | Full 40- or 64-character Git commit SHA. Branch names, tags, and shortened commit hashes aren't supported. |

83| `scope` | No | A repository-relative directory to scan. Omit the value to scan the full repository. |83| `scope` | No | A repository-relative directory to scan. Omit the value to scan the full repository. |

84| `mode` | No | `standard` or `deep`. Omit the value to use the command's selected mode. |84| `mode` | No | `standard` or `deep`. Omit the value to use the command's selected mode. |

85| `prompt` | No | Scan instructions specific to this repository. |

85 86 

86To find a local repository's full commit SHA, run:87To find a local repository's full commit SHA, run:

87 88 


99 --workers 4100 --workers 4

100```101```

101 102 

102`--workers` controls the number of concurrent repository scans and defaults to103`--workers` controls concurrent repository scans and defaults to `4`. It does

103`4`. Use `--mode deep` to select deep scanning for rows without their own104not set the number of discovery workers within each deep scan; configure those

104`mode`. Each CSV row can still choose its own scan mode and repository scope.105limits through [`[deep_scan]`](/codex/security/cli/reference#configure-deep-scans).

106Use `--mode deep` to select deep scanning for rows without their own `mode`.

107Each CSV row can still choose its own scan mode and repository scope.

105 108 

106The CLI checks out each pinned revision, scans the selected target, records the109The CLI checks out each pinned revision, scans the selected target, records the

107result, and removes the temporary repository checkout. A repository counts as110result, and removes the temporary repository checkout. A repository counts as

108complete only when its scan has complete coverage and all required result111complete only when its scan has complete coverage and all required result

109artifacts exist.112artifacts exist.

110 113 

114## Share security context and instructions

115 

116Add architecture documents, threat models, or security policies to every scan

117with `--knowledge-base`. Repeat the flag for more files or directories:

118 

119```bash

120npx @openai/codex-security bulk-scan repositories.csv \

121 --output-dir /path/outside/repositories/security-scans \

122 --knowledge-base /path/to/architecture.md \

123 --knowledge-base /path/to/security-policies

124```

125 

126To add shared scan instructions or run a follow-up after each completed scan,

127provide prompt files:

128 

129```bash

130npx @openai/codex-security bulk-scan repositories.csv \

131 --output-dir /path/outside/repositories/security-scans \

132 --scan-prompt-file scan-instructions.md \

133 --post-scan-prompt-file follow-up.md

134```

135 

136The CLI appends each repository's CSV `prompt` after the shared scan

137instructions. Follow-up instructions run in the same authenticated session only

138after a validated scan has complete coverage. Prompt file paths resolve from

139your current directory.

140 

111## Choose a model and reasoning effort141## Choose a model and reasoning effort

112 142 

113Bulk scans use `gpt-5.6-sol` with `xhigh` reasoning effort by default. To143Bulk scans use `gpt-5.6-sol` with `xhigh` reasoning effort by default. To


129 159 

130Supported effort levels are `minimal`, `low`, `medium`, `high`, and `xhigh`.160Supported effort levels are `minimal`, `low`, `medium`, `high`, and `xhigh`.

131 161 

162To use OpenRouter or Fireworks, set `OPENROUTER_API_KEY` or `FIREWORKS_API_KEY`,

163respectively, and specify `--provider` and `--model`. For credentials and

164examples, see [OpenRouter or Fireworks

165setup](https://learn.chatgpt.com/docs/security/cli/reference#use-openrouter-or-fireworks) or [Amazon

166Bedrock setup](https://learn.chatgpt.com/docs/security/cli/reference#use-amazon-bedrock).

167 

132## Review campaign results168## Review campaign results

133 169 

134The output directory contains the pinned campaign, an append-only results170The output directory contains the pinned campaign, an append-only results


154 └── report.md190 └── report.md

155```191```

156 192 

157- `manifest.json` records the repositories, pinned revisions, scopes, and scan193- `manifest.json` records the repositories, pinned revisions, scopes, scan

158 modes in the campaign.194 modes, and shared or repository-specific instructions in the campaign.

159- `results.jsonl` records each repository attempt, its status, artifact195- `results.jsonl` records each repository attempt, its status, artifact

160 directory, and any available cost or error details.196 directory, and any available cost or error details.

161- `report.md` provides a readable report for one repository attempt.197- `report.md` provides a readable report for one repository attempt.


185 --workers 4221 --workers 4

186```222```

187 223 

188The CLI resumes repositories that still need work. It skips a completed224The CLI resumes unfinished repository scans and skips completed ones. Scans

189repository only when the corresponding receipt and all required scan artifacts225with incomplete coverage aren't retried. Their results remain available, and

190still exist.226the command exits with code `2`.

191 227 

192Don't change the repository inventory for an existing output directory. The CLI228Don't change the repository inventory or scan and follow-up instructions for

193checks the pinned manifest and rejects a different campaign. Use a new output229an existing output directory. The CLI checks the pinned manifest and rejects a

194directory when you change repositories, revisions, scopes, or scan modes.230different campaign. Use a new output directory when you change repositories,

231revisions, scopes, scan modes, or shared or repository-specific instructions.

195 232 

196## Retry repository errors233## Retry repository errors

197 234 


206```243```

207 244 

208The default is one attempt per repository. Every attempt receives its own245The default is one attempt per repository. Every attempt receives its own

209receipt and artifact directory.246receipt and artifact directory. Retries cover checkout errors, scan failures,

247and missing required artifacts. Completed scans with incomplete coverage

248aren't retried.

210 249 

211Bulk scans use these exit codes:250Bulk scans use these exit codes:

212 251 

Details

24 24 

25The runner needs:25The runner needs:

26 26 

27- Node.js 22 or later.27- Node.js 22.13.0 or later.

28- Python 3.10 or later.28- Python 3.10 or later.

29- The published `@openai/codex-security` package, installed outside the29- The published `@openai/codex-security` package, installed outside the

30 repository checkout.30 repository checkout.

Details

71### Can an interrupted bulk scan resume71### Can an interrupted bulk scan resume

72 72 

73Yes. Run the same bulk-scan command with the original CSV and output directory.73Yes. Run the same bulk-scan command with the original CSV and output directory.

74Codex Security skips completed repositories when their recorded scan artifacts74Codex Security skips completed repositories.

75remain intact.

76 75 

77Add `--max-attempts 3` to retry temporary repository or scan errors:76Add `--max-attempts 3` to retry temporary repository or scan errors:

78 77 


83 --max-attempts 382 --max-attempts 3

84```83```

85 84 

85A completed scan with `partial` or `unknown` coverage keeps its results and

86causes the campaign to exit with code `2`. It isn't retried, even with

87`--max-attempts`.

88 

86### How can a scan use architecture and security policies89### How can a scan use architecture and security policies

87 90 

88Pass architecture documents, threat models, or security policies with91Pass architecture documents, threat models, or security policies with


130 133 

131### How do scans distinguish new and known findings134### How do scans distinguish new and known findings

132 135 

133Match findings that share a root cause across the two scans:136Compare findings across the two scans:

134 

135```bash

136npx @openai/codex-security scans match PREVIOUS_SCAN_ID CURRENT_SCAN_ID

137```

138 

139Compare the matched findings:

140 137 

141```bash138```bash

142npx @openai/codex-security scans compare PREVIOUS_SCAN_ID CURRENT_SCAN_ID139npx @openai/codex-security scans compare PREVIOUS_SCAN_ID CURRENT_SCAN_ID

143```140```

144 141 

145The comparison identifies new, persisting, reopened, resolved, and unknown142The comparison automatically matches findings by root cause, reuses saved

143matches, and identifies new, persisting, reopened, resolved, and unknown

146findings. A finding counts as resolved only when the later scan covers its144findings. A finding counts as resolved only when the later scan covers its

147original target and affected path without coverage gaps.145original target and affected path without coverage gaps.

148 146 


177npx @openai/codex-security scans rerun BASELINE_SCAN_ID175npx @openai/codex-security scans rerun BASELINE_SCAN_ID

178```176```

179 177 

180Match the baseline findings to the new scan:178Compare the baseline with the new scan:

181 

182```bash

183npx @openai/codex-security scans match BASELINE_SCAN_ID REPEAT_SCAN_ID

184```

185 

186Compare the matched results:

187 179 

188```bash180```bash

189npx @openai/codex-security scans compare BASELINE_SCAN_ID REPEAT_SCAN_ID181npx @openai/codex-security scans compare BASELINE_SCAN_ID REPEAT_SCAN_ID


202npx @openai/codex-security scans rerun BEFORE_SCAN_ID194npx @openai/codex-security scans rerun BEFORE_SCAN_ID

203```195```

204 196 

205Match the original findings to the new scan:197Compare the original findings with the new scan:

206 

207```bash

208npx @openai/codex-security scans match BEFORE_SCAN_ID AFTER_SCAN_ID

209```

210 

211Compare the matched findings:

212 198 

213```bash199```bash

214npx @openai/codex-security scans compare BEFORE_SCAN_ID AFTER_SCAN_ID200npx @openai/codex-security scans compare BEFORE_SCAN_ID AFTER_SCAN_ID

Details

116 [--provider {openai,openrouter,fireworks,amazon-bedrock}]116 [--provider {openai,openrouter,fireworks,amazon-bedrock}]

117 [--path PATH | --diff BASE | --working-tree]117 [--path PATH | --diff BASE | --working-tree]

118 [--head HEAD] [--base BASE]118 [--head HEAD] [--base BASE]

119 [--knowledge-base PATH]119 [--knowledge-base PATH] [--scan-prompt-file FILE]

120 [--mode {standard,deep}] [--model MODEL]120 [--post-scan-prompt-file FILE]

121 [--mode {standard,deep}] [--workers N]

122 [--subagents N] [--stop-after-no-new N]

123 [--max-discovery-runs N] [--model MODEL]

121 [--effort {minimal,low,medium,high,xhigh}]124 [--effort {minimal,low,medium,high,xhigh}]

122 [--output-dir DIR]125 [--output-dir DIR]

123 [--archive-existing]126 [--archive-existing]

124 [--plugin-path PATH] [--python PATH]127 [--plugin-path PATH] [--python PATH]

125 [--codex KEY=VALUE] [--fail-on-severity LEVEL]128 [--codex KEY=VALUE] [--fail-on-severity LEVEL]

126 [--max-cost USD] [--dry-run] [--verbose]129 [--max-cost USD] [--dry-run] [--headless] [--verbose]

127 [--json] [--format {toon,json,yaml,jsonl}]130 [--json] [--format {toon,json,yaml,jsonl}]

128 [--full-output] [repository]131 [--full-output] [repository]

129```132```


153To make stored credentials the automatic default, run156To make stored credentials the automatic default, run

154`unset OPENAI_API_KEY CODEX_API_KEY`.157`unset OPENAI_API_KEY CODEX_API_KEY`.

155 158 

159### Use OpenRouter or Fireworks

160 

161Select OpenRouter with its API key and an explicit model:

162 

163```bash

164export OPENROUTER_API_KEY="your-openrouter-api-key"

165npx @openai/codex-security scan . \

166 --provider openrouter \

167 --model anthropic/claude-sonnet-4.5

168```

169 

170Select Fireworks with its API key and an explicit model:

171 

172```bash

173export FIREWORKS_API_KEY="your-fireworks-api-key"

174npx @openai/codex-security scan . \

175 --provider fireworks \

176 --model accounts/fireworks/models/qwen3-235b-a22b

177```

178 

179Both providers also support `bulk-scan`.

180 

156### Use Amazon Bedrock181### Use Amazon Bedrock

157 182 

158Select Amazon Bedrock with `--provider amazon-bedrock` and specify an explicit183Select Amazon Bedrock with `--provider amazon-bedrock` and specify an explicit


220npx @openai/codex-security scan . --mode deep245npx @openai/codex-security scan . --mode deep

221```246```

222 247 

248### Configure deep scans

249 

250Use these options with `--mode deep` to control discovery concurrency and

251runtime:

252 

253| Argument | Description |

254| ------------------------ | ----------------------------------------------------------------------- |

255| `--workers N` | Limit on concurrent discovery workers. Defaults to automatic selection. |

256| `--subagents N` | Subagents available to each discovery worker. Defaults to `3`. |

257| `--stop-after-no-new N` | Stop after `N` consecutive runs find no new issues. Defaults to `6`. |

258| `--max-discovery-runs N` | Limit on total discovery runs. Defaults to `60`. |

259 

260`--subagents` accepts zero or a positive integer. The other options require a

261positive integer. These options aren't available for standard scans.

262 

263For example, limit a deep scan to two discovery workers and ten total runs:

264 

265```bash

266npx @openai/codex-security scan . \

267 --mode deep \

268 --workers 2 \

269 --subagents 0 \

270 --stop-after-no-new 3 \

271 --max-discovery-runs 10

272```

273 

274Set persistent defaults in `~/.codex/codex-security/config.toml`, or in

275`$CODEX_HOME/codex-security/config.toml` when you set `CODEX_HOME`:

276 

277```toml

278[deep_scan]

279workers = 2

280subagents = 0

281stop_after_no_new = 3

282max_discovery_runs = 10

283```

284 

285Command-line options override these defaults. `scan --workers` controls

286discovery workers within one scan; `bulk-scan --workers` controls concurrent

287repository scans.

288 

223### Add security context289### Add security context

224 290 

225Use `--knowledge-base PATH` to provide architecture documents, threat models,291Use `--knowledge-base PATH` to provide architecture documents, threat models,


236skips linked directory entries, and keeps extracted document content302skips linked directory entries, and keeps extracted document content

237outside the saved scan results.303outside the saved scan results.

238 304 

305### Add scan instructions

306 

307To add scan instructions, provide a text or Markdown file with

308`--scan-prompt-file`. Use `--post-scan-prompt-file` to run follow-up

309instructions in the same authenticated session after a completed scan with

310complete coverage:

311 

312```bash

313npx @openai/codex-security scan . \

314 --scan-prompt-file security-focus.md \

315 --post-scan-prompt-file follow-up.md

316```

317 

318For example, use the scan prompt to focus on authorization boundaries and ask

319the follow-up to write a new `post-scan-summary.md` in the scan directory.

320 

239### Set output and policy options321### Set output and policy options

240 322 

241Use these options to keep artifacts, preserve earlier results, or create a323Use these options to keep artifacts, preserve earlier results, or create a


247| `--archive-existing` | Move existing results to `DIR.previous-<timestamp>-<id>` and start with an empty output directory. Requires `--output-dir`. |329| `--archive-existing` | Move existing results to `DIR.previous-<timestamp>-<id>` and start with an empty output directory. Requires `--output-dir`. |

248| `--fail-on-severity LEVEL` | Return exit `1` when a completed scan reports a finding at or above `critical`, `high`, `medium`, or `low`. |330| `--fail-on-severity LEVEL` | Return exit `1` when a completed scan reports a finding at or above `critical`, `high`, `medium`, or `low`. |

249| `--max-cost USD` | Stop a scan when its estimated model cost exceeds the specified USD amount. |331| `--max-cost USD` | Stop a scan when its estimated model cost exceeds the specified USD amount. |

250| `--dry-run` | Check the repository, target, output directory, and Codex configuration without starting a scan. |332| `--dry-run` | Check the repository, target, knowledge base, output directory, and Codex configuration without starting a scan. |

333| `--headless` | Show plain-text progress instead of the interactive scan dashboard. |

251| `--verbose` | Print redacted lifecycle, authentication, progress, and cost diagnostics to stderr. |334| `--verbose` | Print redacted lifecycle, authentication, progress, and cost diagnostics to stderr. |

252| `--json` | Print manifest, findings, coverage, paths, and turn metadata as one JSON document. |335| `--json` | Print manifest, findings, coverage, paths, and turn metadata as one JSON document. |

253| `--format FORMAT` | Print the complete scan result as `toon`, `json`, `yaml`, or `jsonl`. |336| `--format FORMAT` | Print the complete scan result as `toon`, `json`, `yaml`, or `jsonl`. |

254| `--full-output` | Print the complete result using the default structured output format. |337| `--full-output` | Print the complete result using the default structured output format. |

255 338 

256The cost limit is an estimate, not a hard spending cap. Requests already in339The cost limit is an estimate, not a hard spending cap. Requests already in

257progress can finish above the limit, and partial scan results remain available.340progress can finish slightly above the limit. If a scan aborts due to the cost

341limit, partial scan results remain available on disk.

258 342 

259When you omit `--output-dir`, results persist under343When you omit `--output-dir`, results persist under

260`$CODEX_HOME/state/plugins/codex-security/scans/<repository>`. `CODEX_HOME`344`$CODEX_HOME/state/plugins/codex-security/scans/<repository>`. `CODEX_HOME`


291 > /path/outside/repository/codex-security.json375 > /path/outside/repository/codex-security.json

292```376```

293 377 

294A dry run checks local inputs without loading credentials, starting Codex, or378A dry run checks local inputs, including knowledge-base documents, without

295probing the plugin's Python interpreter:379loading credentials, starting Codex, or probing the plugin's Python

380interpreter:

296 381 

297```bash382```bash

298npx @openai/codex-security scan . \383npx @openai/codex-security scan . \


309| --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |394| --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |

310| `--auth {auto,chatgpt,api-key}` | Select the scan credentials. The default is `auto`. |395| `--auth {auto,chatgpt,api-key}` | Select the scan credentials. The default is `auto`. |

311| `--provider {openai,openrouter,fireworks,amazon-bedrock}` | Select the inference provider. The default is `openai`. |396| `--provider {openai,openrouter,fireworks,amazon-bedrock}` | Select the inference provider. The default is `openai`. |

312| `--model MODEL` | Select the model. The default is `gpt-5.6-sol`. Required with `--provider amazon-bedrock`. |397| `--model MODEL` | Select the model. The default is `gpt-5.6-sol`. Required for OpenRouter, Fireworks, and Amazon Bedrock. |

313| `--effort {minimal,low,medium,high,xhigh}` | Select the model's reasoning effort. The default is `xhigh`. |398| `--effort {minimal,low,medium,high,xhigh}` | Select the model's reasoning effort. The default is `xhigh`. |

314| `--plugin-path PATH` | Use a Codex Security plugin directory or ZIP to override the bundled plugin. |399| `--plugin-path PATH` | Use a Codex Security plugin directory or ZIP to override the bundled plugin. |

315| `--python PATH` | Select the Python interpreter for the plugin runtime. |400| `--python PATH` | Select the Python interpreter for the plugin runtime. |


360 [--provider {openai,openrouter,fireworks,amazon-bedrock}]445 [--provider {openai,openrouter,fireworks,amazon-bedrock}]

361 [--model MODEL]446 [--model MODEL]

362 [--effort {minimal,low,medium,high,xhigh}]447 [--effort {minimal,low,medium,high,xhigh}]

448 [--knowledge-base PATH]

449 [--scan-prompt-file FILE]

450 [--post-scan-prompt-file FILE]

363 [--max-attempts N] [--plugin-path PATH]451 [--max-attempts N] [--plugin-path PATH]

364 [--python PATH] [--codex KEY=VALUE]452 [--python PATH] [--codex KEY=VALUE]

365```453```


382```470```

383 471 

384The CSV requires `id`, `repository`, and `revision` columns. Revisions must be472The CSV requires `id`, `repository`, and `revision` columns. Revisions must be

385full commit hashes. Optional `scope` and `mode` columns configure individual473full commit hashes. Optional `scope`, `mode`, and `prompt` columns configure

386repositories:474individual repositories:

387 475 

388```csv476```csv

389id,repository,revision,scope,mode477id,repository,revision,scope,mode,prompt

390service,https://github.com/example/service.git,0123456789abcdef0123456789abcdef01234567,src,standard478service,https://github.com/example/service.git,0123456789abcdef0123456789abcdef01234567,src,standard,Review authorization boundaries.

391```479```

392 480 

393`--workers` limits simultaneous scans and defaults to `4`. `--mode` defaults to481Use `--knowledge-base PATH` to share security documents across every

394`standard`, and `--max-attempts` defaults to `1`. Set `--max-attempts` when482repository. Use `--scan-prompt-file FILE` to add shared scan instructions; the

395you want to retry a repository after an error. Run the same command again to483CSV `prompt` column adds repository-specific instructions after that shared

396resume a bulk scan from its existing output directory. The CLI skips completed484prompt. `--post-scan-prompt-file FILE` runs follow-up instructions after each

397repositories only when their recorded result artifacts are still present.485completed scan with complete coverage.

486 

487`--workers` limits simultaneous repository scans and defaults to `4`. `--mode`

488defaults to `standard`, and `--max-attempts` defaults to `1`. Set

489`--max-attempts` to retry repository or scan errors. Completed scans with

490incomplete coverage aren't retried. Their results remain available, and the

491command returns exit code `2`.

492 

493Run the same command again to resume from an existing output directory. The CLI

494skips completed scans, including scans with incomplete coverage.

398 495 

399For containerized campaigns, see [Run bulk scans in496For containerized campaigns, see [Run bulk scans in

400Docker](https://learn.chatgpt.com/docs/security/cli/bulk-scans#run-bulk-scans-in-docker).497Docker](https://learn.chatgpt.com/docs/security/cli/bulk-scans#run-bulk-scans-in-docker).


437 534 

438### Match and compare findings535### Match and compare findings

439 536 

440Match findings that share the same root cause across two scans:537Compare two scans to find new, persisting, reopened, resolved, and unknown

538findings:

441 539 

442```bash540```bash

443npx @openai/codex-security scans match PREVIOUS_SCAN_ID CURRENT_SCAN_ID541npx @openai/codex-security scans compare PREVIOUS_SCAN_ID CURRENT_SCAN_ID

444```542```

445 543 

446Compare the matched scans to find new, persisting, reopened, resolved, and544The comparison automatically matches findings that share the same root cause

447unknown findings:545and reuses saved matches. To save matches explicitly, use `scans match`:

448 546 

449```bash547```bash

450npx @openai/codex-security scans compare PREVIOUS_SCAN_ID CURRENT_SCAN_ID548npx @openai/codex-security scans match PREVIOUS_SCAN_ID CURRENT_SCAN_ID

451```549```

452 550 

453A finding is unknown when the later scan has incomplete coverage or doesn't551A finding is unknown when the later scan has incomplete coverage or doesn't


639without writing the complete scan result to stdout. Request `--json`,737without writing the complete scan result to stdout. Request `--json`,

640`--format`, or `--full-output` to send structured scan results to stdout.738`--format`, or `--full-output` to send structured scan results to stdout.

641 739 

740Interactive terminals show a live dashboard with the current scan phase,

741reviewed files, activity, token usage, and estimated cost. CI and redirected

742output use plain-text progress. Add `--headless` to use plain-text progress in

743an interactive terminal:

744 

745```bash

746npx @openai/codex-security scan . --headless

747```

748 

642### Verbose diagnostics749### Verbose diagnostics

643 750 

644Add `--verbose` to print redacted lifecycle, authentication, progress, and cost751Add `--verbose` to print redacted lifecycle, authentication, progress, and cost


758 865 

759Set `OPENAI_API_KEY` or `CODEX_API_KEY`, sign in with866Set `OPENAI_API_KEY` or `CODEX_API_KEY`, sign in with

760`npx @openai/codex-security login`, or use an existing file-backed Codex867`npx @openai/codex-security login`, or use an existing file-backed Codex

761sign-in. For Amazon Bedrock, use a Bedrock API key or the standard AWS868sign-in. For OpenRouter or Fireworks, set the provider's API key and select a

869model. For Amazon Bedrock, use a Bedrock API key or the standard AWS

762credential chain instead.870credential chain instead.

763 871 

764For credential selection, see [Select scan872For credential selection, see [Select scan


766 874 

767For CI, keep the API key scoped to the scan step and use a trusted workflow.875For CI, keep the API key scoped to the scan step and use a trusted workflow.

768 876 

769The CLI requires Node.js 22 or later. Running a scan or exporting findings also877The CLI requires Node.js 22.13.0 or later. Running a scan or exporting findings

770requires Python 3.10 or later. Python 3.10 also requires `tomli`. Use `--python`878also requires Python 3.10 or later. Python 3.10 also requires `tomli`. Use

771or `PYTHON` to select an interpreter when automatic discovery is unsuitable.879`--python` or `PYTHON` to select an interpreter when automatic discovery is

880unsuitable.

772 881 

773Continue with the [CLI quickstart](https://learn.chatgpt.com/docs/security/cli), [bulk-scan882Continue with the [CLI quickstart](https://learn.chatgpt.com/docs/security/cli), [bulk-scan

774guide](https://learn.chatgpt.com/docs/security/cli/bulk-scans), [CLI FAQ](https://learn.chatgpt.com/docs/security/cli/faq), [CI883guide](https://learn.chatgpt.com/docs/security/cli/bulk-scans), [CLI FAQ](https://learn.chatgpt.com/docs/security/cli/faq), [CI

security/sdk.md +72 −12

Details

7findings, coverage details, and paths to scan artifacts. For longer scans, it7findings, coverage details, and paths to scan artifacts. For longer scans, it

8supports preflight checks, cost limits, progress callbacks, and cancellation.8supports preflight checks, cost limits, progress callbacks, and cancellation.

9 9 

10The SDK uses ECMAScript modules (ESM) and runs server-side with Node.js 22 or10The SDK uses ECMAScript modules (ESM) and runs server-side with Node.js 22.13.0

11later. Scanning also requires Python 3.10 or later.11or later. Scanning also requires Python 3.10 or later.

12 12 

13The Codex Security SDK is [publicly available on13The Codex Security SDK is [publicly available on

14 GitHub](https://github.com/openai/codex-security). Running scans requires14 GitHub](https://github.com/openai/codex-security). Running scans requires


25```25```

26 26 

27Before starting a scan, set `OPENAI_API_KEY` or `CODEX_API_KEY`, use an27Before starting a scan, set `OPENAI_API_KEY` or `CODEX_API_KEY`, use an

28existing file-backed Codex sign-in, or [configure Amazon28existing file-backed Codex sign-in, or [configure another

29Bedrock](#configure-the-runtime-and-credentials) with AWS credentials and29provider](#configure-the-runtime-and-credentials). Amazon Bedrock uses AWS

30explicit `model_provider` and `model` overrides.30credentials; OpenRouter and Fireworks use provider-specific API keys and

31configuration.

31 32 

32For best results, use an account verified for [Trusted Access for33For best results, use an account verified for [Trusted Access for

33Cyber](https://chatgpt.com/cyber). Signing in or providing an API key does not34Cyber](https://chatgpt.com/cyber). Signing in or providing an API key does not


67 68 

68## Check inputs with preflight69## Check inputs with preflight

69 70 

70Use `preflight` to check a repository, target, mode, output location, and71Use `preflight` to check a repository, target, mode, knowledge-base documents,

71Codex configuration before starting a scan:72output location, and Codex configuration before starting a scan:

72 73 

73```ts74```ts

74const plan = await security.preflight("/path/to/repository", {75const plan = await security.preflight("/path/to/repository", {

75 target: ["services/billing", "packages/auth"],76 target: ["services/billing", "packages/auth"],

77 knowledgeBasePaths: ["/path/to/architecture.md"],

76 outputDir: "/path/outside/repository/results",78 outputDir: "/path/outside/repository/results",

77});79});

78 80 


173const result = await security.run("/path/to/repository", {175const result = await security.run("/path/to/repository", {

174 target: ["services/billing"],176 target: ["services/billing"],

175 mode: "deep",177 mode: "deep",

178 workers: 2,

179 subagents: 0,

180 stopAfterNoNew: 3,

181 maxDiscoveryRuns: 10,

176});182});

177```183```

178 184 

179Deep mode supports repository and path targets. Use standard mode for diff and185Deep mode supports repository and path targets. Use standard mode for diff and

180working-tree scans.186working-tree scans. The optional settings control concurrent discovery workers,

187subagents per worker, consecutive discovery runs without new findings, and the

188total number of discovery runs. They require `mode: "deep"`.

181 189 

182### Add a security knowledge base190### Add a security knowledge base

183 191 


198The SDK rejects linked input paths, skips linked directory entries, and keeps206The SDK rejects linked input paths, skips linked directory entries, and keeps

199extracted document content outside the saved scan results.207extracted document content outside the saved scan results.

200 208 

209### Add scan and follow-up instructions

210 

211Use `scanPrompt` to focus the scan and `postScanPrompt` to request a follow-up

212after a completed scan:

213 

214```ts

215const result = await security.run("/path/to/repository", {

216 scanPrompt: "Focus on tenant isolation and authorization checks.",

217 postScanPrompt: "Write confirmed findings to post-scan-summary.md.",

218});

219```

220 

221The follow-up runs in the same authenticated session only after the scan

222finishes with complete coverage.

223 

201### Set a scan budget224### Set a scan budget

202 225 

203Set `maxCostUsd` to stop a scan when its estimated model cost exceeds a limit.226Set `maxCostUsd` to stop a scan when its estimated model cost exceeds a limit.


214console.log(result.cost?.estimatedUsd);237console.log(result.cost?.estimatedUsd);

215```238```

216 239 

217The limit is an estimate, not a hard spending cap. Requests already in progress240The limit estimates spending but isn't a hard cap, so requests already in

218can finish above it. If the scan exceeds the limit, the SDK throws241progress can finish slightly above it. If the scan exceeds the limit, the SDK

219`ScanCostLimitExceededError` and preserves the available results.242throws `ScanCostLimitExceededError` and preserves the available results.

220 243 

221## Work with scan results244## Work with scan results

222 245 


278 onScanStarted() {301 onScanStarted() {

279 console.log("Scan started");302 console.log("Scan started");

280 },303 },

304 onProgress(progress) {

305 console.log(progress.phase, progress.filesCompleted, progress.filesTotal);

306 },

281 onWorkerStatus(status) {307 onWorkerStatus(status) {

282 console.log(status.kind, status);308 console.log(status.kind, status);

283 },309 },


324lifecycle callbacks:350lifecycle callbacks:

325 351 

326| Callback | Called when |352| Callback | Called when |

327| ----------------------------------- | ------------------------------------------------ |353| ----------------------------------- | ---------------------------------------------------- |

354| `onAuthentication(authentication)` | The scan selects its authentication method. |

328| `onOutputArchived(archiveDir)` | Existing results move to the archive directory. |355| `onOutputArchived(archiveDir)` | Existing results move to the archive directory. |

329| `onOutputDirReady(scanDir)` | The private scan directory is ready. |356| `onOutputDirReady(scanDir)` | The private scan directory is ready. |

330| `onScanStarted()` | Scan setup completes and execution begins. |357| `onScanStarted()` | Scan setup completes and execution begins. |

358| `onTrustedAccessStatus(status)` | Trusted Access status becomes available. |

331| `onReconnect(attempt, maxAttempts)` | The SDK retries a disconnected scan stream. |359| `onReconnect(attempt, maxAttempts)` | The SDK retries a disconnected scan stream. |

360| `onActivity(activity)` | A command, tool, reasoning step, or message updates. |

361| `onProgress(progress)` | The scan phase or reviewed file count changes. |

332| `onWorkerStatus(status)` | Worker preflight or dispatch status changes. |362| `onWorkerStatus(status)` | Worker preflight or dispatch status changes. |

333| `onCost(cost)` | An updated estimated scan cost is available. |363| `onCost(cost)` | An updated estimated scan cost is available. |

364| `onWarning(warning)` | The scan reports a warning. |

334| `onObserverError(observer, error)` | Another scan lifecycle callback raises an error. |365| `onObserverError(observer, error)` | Another scan lifecycle callback raises an error. |

335 366 

367Trusted Access status is `granted`, `not_granted`, or `unknown`. Missing or

368unknown access also triggers `onWarning`.

369 

336## Configure the runtime and credentials370## Configure the runtime and credentials

337 371 

338Pass runtime configuration when you need a specific plugin, interpreter, or372Pass runtime configuration when you need a specific plugin, interpreter, or


357Bedrock](https://learn.chatgpt.com/docs/security/cli/reference#use-amazon-bedrock), set391Bedrock](https://learn.chatgpt.com/docs/security/cli/reference#use-amazon-bedrock), set

358`model_provider` and `model` in `codexOverrides`.392`model_provider` and `model` in `codexOverrides`.

359 393 

394For OpenRouter or Fireworks, also provide the matching API key and a complete

395provider configuration in `codexOverrides`. For example, set

396`OPENROUTER_API_KEY` and configure OpenRouter:

397 

398```ts

399const security = new CodexSecurity({

400 codexOverrides: {

401 model: "anthropic/claude-sonnet-4.5",

402 model_provider: "openrouter",

403 model_providers: {

404 openrouter: {

405 name: "OpenRouter",

406 base_url: "https://openrouter.ai/api/v1",

407 env_key: "OPENROUTER_API_KEY",

408 wire_api: "responses",

409 },

410 },

411 },

412});

413```

414 

415For Fireworks, change both `openrouter` keys to `fireworks`, set `name` to

416`Fireworks AI`, set `env_key` to `FIREWORKS_API_KEY`, use

417`https://api.fireworks.ai/inference/v1` as `base_url`, and select a Fireworks

418model.

419 

360The client also exposes supported authentication methods:420The client also exposes supported authentication methods:

361 421 

362| Method | Purpose |422| Method | Purpose |