codex-manual.md +327 −101
3581#### Can an interrupted bulk scan resume3581#### Can an interrupted bulk scan resume
3582 3582
3583Yes. Run the same bulk-scan command with the original CSV and output directory.3583Yes. Run the same bulk-scan command with the original CSV and output directory.
35843584Codex Security skips completed repositories when their recorded scan artifactsCodex Security skips completed repositories.
3585remain intact.
3586 3585
3587Add `--max-attempts 3` to retry temporary repository or scan errors:3586Add `--max-attempts 3` to retry temporary repository or scan errors:
3588 3587
3593 --max-attempts 33592 --max-attempts 3
3594```3593```
3595 3594
3595A completed scan with `partial` or `unknown` coverage keeps its results and
3596causes the campaign to exit with code `2`. It isn't retried, even with
3597`--max-attempts`.
3598
3596#### How can a scan use architecture and security policies3599#### How can a scan use architecture and security policies
3597 3600
3598Pass architecture documents, threat models, or security policies with3601Pass architecture documents, threat models, or security policies with
3640 3643
3641#### How do scans distinguish new and known findings3644#### How do scans distinguish new and known findings
3642 3645
36433646Match findings that share a root cause across the two scans:Compare findings across the two scans:
3644
3645```bash
3646npx @openai/codex-security scans match PREVIOUS_SCAN_ID CURRENT_SCAN_ID
3647```
3648
3649Compare the matched findings:
3650 3647
3651```bash3648```bash
3652npx @openai/codex-security scans compare PREVIOUS_SCAN_ID CURRENT_SCAN_ID3649npx @openai/codex-security scans compare PREVIOUS_SCAN_ID CURRENT_SCAN_ID
3653```3650```
3654 3651
36553652The comparison identifies new, persisting, reopened, resolved, and unknownThe comparison automatically matches findings by root cause, reuses saved
3653matches, and identifies new, persisting, reopened, resolved, and unknown
3656findings. A finding counts as resolved only when the later scan covers its3654findings. A finding counts as resolved only when the later scan covers its
3657original target and affected path without coverage gaps.3655original target and affected path without coverage gaps.
3658 3656
3687npx @openai/codex-security scans rerun BASELINE_SCAN_ID3685npx @openai/codex-security scans rerun BASELINE_SCAN_ID
3688```3686```
3689 3687
36903688Match the baseline findings to the new scan:Compare the baseline with the new scan:
3691
3692```bash
3693npx @openai/codex-security scans match BASELINE_SCAN_ID REPEAT_SCAN_ID
3694```
3695
3696Compare the matched results:
3697 3689
3698```bash3690```bash
3699npx @openai/codex-security scans compare BASELINE_SCAN_ID REPEAT_SCAN_ID3691npx @openai/codex-security scans compare BASELINE_SCAN_ID REPEAT_SCAN_ID
3712npx @openai/codex-security scans rerun BEFORE_SCAN_ID3704npx @openai/codex-security scans rerun BEFORE_SCAN_ID
3713```3705```
3714 3706
37153707Match the original findings to the new scan:Compare the original findings with the new scan:
3716
3717```bash
3718npx @openai/codex-security scans match BEFORE_SCAN_ID AFTER_SCAN_ID
3719```
3720
3721Compare the matched findings:
3722 3708
3723```bash3709```bash
3724npx @openai/codex-security scans compare BEFORE_SCAN_ID AFTER_SCAN_ID3710npx @openai/codex-security scans compare BEFORE_SCAN_ID AFTER_SCAN_ID
3803 3789
3804#### Check the prerequisites3790#### Check the prerequisites
3805 3791
38063792The CLI requires Node.js 22 or later. Running a scan or exporting findings alsoThe CLI requires Node.js 22.13.0 or later. Running a scan or exporting findings
38073793requires Python 3.10 or later. For more detail, see [Authentication andalso requires Python 3.10 or later. For more detail, see [Authentication and
3808prerequisites](https://learn.chatgpt.com/docs/security/cli/reference#authentication-and-prerequisites).3794prerequisites](https://learn.chatgpt.com/docs/security/cli/reference#authentication-and-prerequisites).
3809 3795
3810#### Set up and verify the CLI3796#### Set up and verify the CLI
3844```3830```
3845 3831
3846For AWS credentials, see [Amazon Bedrock3832For AWS credentials, see [Amazon Bedrock
38473833setup](https://learn.chatgpt.com/docs/security/cli/reference#use-amazon-bedrock).setup](https://learn.chatgpt.com/docs/security/cli/reference#use-amazon-bedrock). For [OpenRouter or
3834Fireworks](https://learn.chatgpt.com/docs/security/cli/reference#use-openrouter-or-fireworks), set the
3835provider's API key and select a model with `--provider` and `--model`.
3848 3836
3849To use your ChatGPT sign-in when an API key is also set, select it explicitly:3837To use your ChatGPT sign-in when an API key is also set, select it explicitly:
3850 3838
3887npx @openai/codex-security scan "$REPOSITORY" --output-dir "$SCAN_DIR" --dry-run3875npx @openai/codex-security scan "$REPOSITORY" --output-dir "$SCAN_DIR" --dry-run
3888```3876```
3889 3877
38903878The dry run checks local inputs without starting Codex, loading credentials,The dry run checks local inputs, including any `--knowledge-base` paths,
38913879or probing the plugin's Python interpreter.without starting Codex, loading credentials, or probing the plugin's Python
3880interpreter.
3892 3881
3893#### Run your first scan3882#### Run your first scan
3894 3883
3898npx @openai/codex-security scan "$REPOSITORY" --output-dir "$SCAN_DIR"3887npx @openai/codex-security scan "$REPOSITORY" --output-dir "$SCAN_DIR"
3899```3888```
3900 3889
3890Interactive terminals show a live scan dashboard. Add `--headless` to show
3891plain progress lines instead. CI and terminals without an interactive session
3892use plain progress automatically.
3893
3901By default, the CLI writes scan progress and its completion summary to stderr.3894By default, the CLI writes scan progress and its completion summary to stderr.
3902It doesn't print the full scan result to stdout. A completed scan prints a3895It doesn't print the full scan result to stdout. A completed scan prints a
3903summary like this:3896summary like this:
3992npx @openai/codex-security scan "$REPOSITORY" --mode deep3985npx @openai/codex-security scan "$REPOSITORY" --mode deep
3993```3986```
3994 3987
39953988Deep mode supports repository and path targets, not diff or working-tree scans.To control discovery workers, subagents, and when the scan stops:
3989
3990```bash
3991npx @openai/codex-security scan "$REPOSITORY" \
3992 --mode deep \
3993 --workers 2 \
3994 --subagents 0 \
3995 --stop-after-no-new 3 \
3996 --max-discovery-runs 10
3997```
3998
3999These options require deep mode, which supports repository and path targets,
4000not diff or working-tree scans. Here, `--workers` controls discovery workers
4001within one scan; `bulk-scan --workers` controls concurrent repository scans.
3996 4002
3997#### Add architecture and security context4003#### Add architecture and security context
3998 4004
4006 --knowledge-base /path/to/security-policies4012 --knowledge-base /path/to/security-policies
4007```4013```
4008 4014
4015#### Add custom scan instructions
4016
4017Add instructions that focus the scan on your security priorities. Use a
4018second file for a follow-up after a validated scan with complete coverage:
4019
4020```bash
4021npx @openai/codex-security scan "$REPOSITORY" \
4022 --scan-prompt-file /path/to/scan.md \
4023 --post-scan-prompt-file /path/to/follow-up.md
4024```
4025
4026The follow-up runs in the same authenticated session. Both options also work
4027with `bulk-scan`; a CSV `prompt` column adds repository-specific instructions.
4028
4009#### Set a scan budget4029#### Set a scan budget
4010 4030
4011Use `--max-cost` to stop a scan when its estimated model cost exceeds a limit4031Use `--max-cost` to stop a scan when its estimated model cost exceeds a limit
4015npx @openai/codex-security scan "$REPOSITORY" --max-cost 54035npx @openai/codex-security scan "$REPOSITORY" --max-cost 5
4016```4036```
4017 4037
40184038Requests already in progress can finish above the limit. Codex Security keepsRequests already in progress can finish slightly above the limit. If a scan
40194039the available results when a scan stops.aborts due to the cost limit, partial scan results remain available on disk.
4020 4040
4021#### Scan changes before each commit4041#### Scan changes before each commit
4022 4042
4055 --workers 44075 --workers 4
4056```4076```
4057 4077
40584078Run the same command again to resume an existing bulk scan. CompletedRun the same command again to resume an existing bulk scan. Codex Security
40594079repositories with intact result artifacts aren't scanned again. Addskips completed repositories. Add `--max-attempts 3` when you want to retry
40604080`--max-attempts 3` when you want to retry temporary repository or scan errors.temporary repository or scan errors.
4061 4081
4062For GitHub discovery, CSV preparation, campaign results, and Docker setup, see4082For GitHub discovery, CSV preparation, campaign results, and Docker setup, see
4063[Run bulk security scans](https://learn.chatgpt.com/docs/security/cli/bulk-scans).4083[Run bulk security scans](https://learn.chatgpt.com/docs/security/cli/bulk-scans).
4077 --workers 44097 --workers 4
4078```4098```
4079 4099
40804100The container runs bulk scans without prompts. Use the CLI outside Docker whenThe container runs bulk scans without interactive prompts. Use the CLI outside
40814101you want to discover repositories interactively. For private repositories,Docker when you want to discover repositories interactively. For private
40824102provide `GH_TOKEN` or `GITHUB_TOKEN` through your environment or secretrepositories, provide `GH_TOKEN` or `GITHUB_TOKEN` through your environment or
40834103manager. The [sign-in requirements](#sign-in), including account and repositorysecret manager. The [sign-in requirements](#sign-in), including account and
40844104access, also apply to containerized scans.repository access, also apply to containerized scans.
4085 4105
4086#### Revisit a saved scan4106#### Revisit a saved scan
4087 4107
4113npx @openai/codex-security scans rerun SCAN_ID4133npx @openai/codex-security scans rerun SCAN_ID
4114```4134```
4115 4135
41164136To compare two scans, first match findings that share the same root cause:Compare two scans to find new, persisting, reopened, resolved, or unknown
41174137 findings:
4118```bash
4119npx @openai/codex-security scans match PREVIOUS_SCAN_ID CURRENT_SCAN_ID
4120```
4121
4122Then check which findings are new, persisting, reopened, resolved, or unknown:
4123 4138
4124```bash4139```bash
4125npx @openai/codex-security scans compare PREVIOUS_SCAN_ID CURRENT_SCAN_ID4140npx @openai/codex-security scans compare PREVIOUS_SCAN_ID CURRENT_SCAN_ID
4126```4141```
4127 4142
4143The comparison automatically matches findings by root cause and reuses saved
4144matches.
4145
4128For the bulk-scan CSV format, scan-history filters, and command options, see4146For the bulk-scan CSV format, scan-history filters, and command options, see
4129the [CLI reference](https://learn.chatgpt.com/docs/security/cli/reference).4147the [CLI reference](https://learn.chatgpt.com/docs/security/cli/reference).
4130 4148
4259 [--provider {openai,openrouter,fireworks,amazon-bedrock}]4277 [--provider {openai,openrouter,fireworks,amazon-bedrock}]
4260 [--path PATH | --diff BASE | --working-tree]4278 [--path PATH | --diff BASE | --working-tree]
4261 [--head HEAD] [--base BASE]4279 [--head HEAD] [--base BASE]
42624280 [--knowledge-base PATH] [--knowledge-base PATH] [--scan-prompt-file FILE]
42634281 [--mode {standard,deep}] [--model MODEL] [--post-scan-prompt-file FILE]
4282 [--mode {standard,deep}] [--workers N]
4283 [--subagents N] [--stop-after-no-new N]
4284 [--max-discovery-runs N] [--model MODEL]
4264 [--effort {minimal,low,medium,high,xhigh}]4285 [--effort {minimal,low,medium,high,xhigh}]
4265 [--output-dir DIR]4286 [--output-dir DIR]
4266 [--archive-existing]4287 [--archive-existing]
4267 [--plugin-path PATH] [--python PATH]4288 [--plugin-path PATH] [--python PATH]
4268 [--codex KEY=VALUE] [--fail-on-severity LEVEL]4289 [--codex KEY=VALUE] [--fail-on-severity LEVEL]
42694290 [--max-cost USD] [--dry-run] [--verbose] [--max-cost USD] [--dry-run] [--headless] [--verbose]
4270 [--json] [--format {toon,json,yaml,jsonl}]4291 [--json] [--format {toon,json,yaml,jsonl}]
4271 [--full-output] [repository]4292 [--full-output] [repository]
4272```4293```
4296To make stored credentials the automatic default, run4317To make stored credentials the automatic default, run
4297`unset OPENAI_API_KEY CODEX_API_KEY`.4318`unset OPENAI_API_KEY CODEX_API_KEY`.
4298 4319
4320#### Use OpenRouter or Fireworks
4321
4322Select OpenRouter with its API key and an explicit model:
4323
4324```bash
4325export OPENROUTER_API_KEY="your-openrouter-api-key"
4326npx @openai/codex-security scan . \
4327 --provider openrouter \
4328 --model anthropic/claude-sonnet-4.5
4329```
4330
4331Select Fireworks with its API key and an explicit model:
4332
4333```bash
4334export FIREWORKS_API_KEY="your-fireworks-api-key"
4335npx @openai/codex-security scan . \
4336 --provider fireworks \
4337 --model accounts/fireworks/models/qwen3-235b-a22b
4338```
4339
4340Both providers also support `bulk-scan`.
4341
4299#### Use Amazon Bedrock4342#### Use Amazon Bedrock
4300 4343
4301Select Amazon Bedrock with `--provider amazon-bedrock` and specify an explicit4344Select Amazon Bedrock with `--provider amazon-bedrock` and specify an explicit
4363npx @openai/codex-security scan . --mode deep4406npx @openai/codex-security scan . --mode deep
4364```4407```
4365 4408
4409#### Configure deep scans
4410
4411Use these options with `--mode deep` to control discovery concurrency and
4412runtime:
4413
4414| Argument | Description |
4415| ------------------------ | ----------------------------------------------------------------------- |
4416| `--workers N` | Limit on concurrent discovery workers. Defaults to automatic selection. |
4417| `--subagents N` | Subagents available to each discovery worker. Defaults to `3`. |
4418| `--stop-after-no-new N` | Stop after `N` consecutive runs find no new issues. Defaults to `6`. |
4419| `--max-discovery-runs N` | Limit on total discovery runs. Defaults to `60`. |
4420
4421`--subagents` accepts zero or a positive integer. The other options require a
4422positive integer. These options aren't available for standard scans.
4423
4424For example, limit a deep scan to two discovery workers and ten total runs:
4425
4426```bash
4427npx @openai/codex-security scan . \
4428 --mode deep \
4429 --workers 2 \
4430 --subagents 0 \
4431 --stop-after-no-new 3 \
4432 --max-discovery-runs 10
4433```
4434
4435Set persistent defaults in `~/.codex/codex-security/config.toml`, or in
4436`$CODEX_HOME/codex-security/config.toml` when you set `CODEX_HOME`:
4437
4438```toml
4439[deep_scan]
4440workers = 2
4441subagents = 0
4442stop_after_no_new = 3
4443max_discovery_runs = 10
4444```
4445
4446Command-line options override these defaults. `scan --workers` controls
4447discovery workers within one scan; `bulk-scan --workers` controls concurrent
4448repository scans.
4449
4366#### Add security context4450#### Add security context
4367 4451
4368Use `--knowledge-base PATH` to provide architecture documents, threat models,4452Use `--knowledge-base PATH` to provide architecture documents, threat models,
4379skips linked directory entries, and keeps extracted document content4463skips linked directory entries, and keeps extracted document content
4380outside the saved scan results.4464outside the saved scan results.
4381 4465
4466#### Add scan instructions
4467
4468To add scan instructions, provide a text or Markdown file with
4469`--scan-prompt-file`. Use `--post-scan-prompt-file` to run follow-up
4470instructions in the same authenticated session after a completed scan with
4471complete coverage:
4472
4473```bash
4474npx @openai/codex-security scan . \
4475 --scan-prompt-file security-focus.md \
4476 --post-scan-prompt-file follow-up.md
4477```
4478
4479For example, use the scan prompt to focus on authorization boundaries and ask
4480the follow-up to write a new `post-scan-summary.md` in the scan directory.
4481
4382#### Set output and policy options4482#### Set output and policy options
4383 4483
4384Use these options to keep artifacts, preserve earlier results, or create a4484Use these options to keep artifacts, preserve earlier results, or create a
4390| `--archive-existing` | Move existing results to `DIR.previous--` and start with an empty output directory. Requires `--output-dir`. |4490| `--archive-existing` | Move existing results to `DIR.previous--` and start with an empty output directory. Requires `--output-dir`. |
4391| `--fail-on-severity LEVEL` | Return exit `1` when a completed scan reports a finding at or above `critical`, `high`, `medium`, or `low`. |4491| `--fail-on-severity LEVEL` | Return exit `1` when a completed scan reports a finding at or above `critical`, `high`, `medium`, or `low`. |
4392| `--max-cost USD` | Stop a scan when its estimated model cost exceeds the specified USD amount. |4492| `--max-cost USD` | Stop a scan when its estimated model cost exceeds the specified USD amount. |
43934493| `--dry-run` | Check the repository, target, output directory, and Codex configuration without starting a scan. || `--dry-run` | Check the repository, target, knowledge base, output directory, and Codex configuration without starting a scan. |
4494| `--headless` | Show plain-text progress instead of the interactive scan dashboard. |
4394| `--verbose` | Print redacted lifecycle, authentication, progress, and cost diagnostics to stderr. |4495| `--verbose` | Print redacted lifecycle, authentication, progress, and cost diagnostics to stderr. |
4395| `--json` | Print manifest, findings, coverage, paths, and turn metadata as one JSON document. |4496| `--json` | Print manifest, findings, coverage, paths, and turn metadata as one JSON document. |
4396| `--format FORMAT` | Print the complete scan result as `toon`, `json`, `yaml`, or `jsonl`. |4497| `--format FORMAT` | Print the complete scan result as `toon`, `json`, `yaml`, or `jsonl`. |
4397| `--full-output` | Print the complete result using the default structured output format. |4498| `--full-output` | Print the complete result using the default structured output format. |
4398 4499
4399The cost limit is an estimate, not a hard spending cap. Requests already in4500The cost limit is an estimate, not a hard spending cap. Requests already in
44004501progress can finish above the limit, and partial scan results remain available.progress can finish slightly above the limit. If a scan aborts due to the cost
4502limit, partial scan results remain available on disk.
4401 4503
4402When you omit `--output-dir`, results persist under4504When you omit `--output-dir`, results persist under
4403`$CODEX_HOME/state/plugins/codex-security/scans/`. `CODEX_HOME`4505`$CODEX_HOME/state/plugins/codex-security/scans/`. `CODEX_HOME`
4434 > /path/outside/repository/codex-security.json4536 > /path/outside/repository/codex-security.json
4435```4537```
4436 4538
44374539A dry run checks local inputs without loading credentials, starting Codex, orA dry run checks local inputs, including knowledge-base documents, without
44384540probing the plugin's Python interpreter:loading credentials, starting Codex, or probing the plugin's Python
4541interpreter:
4439 4542
4440```bash4543```bash
4441npx @openai/codex-security scan . \4544npx @openai/codex-security scan . \
4452| --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |4555| --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
4453| `--auth {auto,chatgpt,api-key}` | Select the scan credentials. The default is `auto`. |4556| `--auth {auto,chatgpt,api-key}` | Select the scan credentials. The default is `auto`. |
4454| `--provider {openai,openrouter,fireworks,amazon-bedrock}` | Select the inference provider. The default is `openai`. |4557| `--provider {openai,openrouter,fireworks,amazon-bedrock}` | Select the inference provider. The default is `openai`. |
44554558| `--model MODEL` | Select the model. The default is `gpt-5.6-sol`. Required with `--provider amazon-bedrock`. || `--model MODEL` | Select the model. The default is `gpt-5.6-sol`. Required for OpenRouter, Fireworks, and Amazon Bedrock. |
4456| `--effort {minimal,low,medium,high,xhigh}` | Select the model's reasoning effort. The default is `xhigh`. |4559| `--effort {minimal,low,medium,high,xhigh}` | Select the model's reasoning effort. The default is `xhigh`. |
4457| `--plugin-path PATH` | Use a Codex Security plugin directory or ZIP to override the bundled plugin. |4560| `--plugin-path PATH` | Use a Codex Security plugin directory or ZIP to override the bundled plugin. |
4458| `--python PATH` | Select the Python interpreter for the plugin runtime. |4561| `--python PATH` | Select the Python interpreter for the plugin runtime. |
4503 [--provider {openai,openrouter,fireworks,amazon-bedrock}]4606 [--provider {openai,openrouter,fireworks,amazon-bedrock}]
4504 [--model MODEL]4607 [--model MODEL]
4505 [--effort {minimal,low,medium,high,xhigh}]4608 [--effort {minimal,low,medium,high,xhigh}]
4609 [--knowledge-base PATH]
4610 [--scan-prompt-file FILE]
4611 [--post-scan-prompt-file FILE]
4506 [--max-attempts N] [--plugin-path PATH]4612 [--max-attempts N] [--plugin-path PATH]
4507 [--python PATH] [--codex KEY=VALUE]4613 [--python PATH] [--codex KEY=VALUE]
4508```4614```
4525```4631```
4526 4632
4527The CSV requires `id`, `repository`, and `revision` columns. Revisions must be4633The CSV requires `id`, `repository`, and `revision` columns. Revisions must be
45284634full commit hashes. Optional `scope` and `mode` columns configure individualfull commit hashes. Optional `scope`, `mode`, and `prompt` columns configure
45294635repositories:individual repositories:
4530 4636
4531```csv4637```csv
45324638id,repository,revision,scope,modeid,repository,revision,scope,mode,prompt
45334639service,https://github.com/example/service.git,0123456789abcdef0123456789abcdef01234567,src,standardservice,https://github.com/example/service.git,0123456789abcdef0123456789abcdef01234567,src,standard,Review authorization boundaries.
4534```4640```
4535 4641
45364642`--workers` limits simultaneous scans and defaults to `4`. `--mode` defaults toUse `--knowledge-base PATH` to share security documents across every
45374643`standard`, and `--max-attempts` defaults to `1`. Set `--max-attempts` whenrepository. Use `--scan-prompt-file FILE` to add shared scan instructions; the
45384644you want to retry a repository after an error. Run the same command again toCSV `prompt` column adds repository-specific instructions after that shared
45394645resume a bulk scan from its existing output directory. The CLI skips completedprompt. `--post-scan-prompt-file FILE` runs follow-up instructions after each
45404646repositories only when their recorded result artifacts are still present.completed scan with complete coverage.
4647
4648`--workers` limits simultaneous repository scans and defaults to `4`. `--mode`
4649defaults to `standard`, and `--max-attempts` defaults to `1`. Set
4650`--max-attempts` to retry repository or scan errors. Completed scans with
4651incomplete coverage aren't retried. Their results remain available, and the
4652command returns exit code `2`.
4653
4654Run the same command again to resume from an existing output directory. The CLI
4655skips completed scans, including scans with incomplete coverage.
4541 4656
4542For containerized campaigns, see [Run bulk scans in4657For containerized campaigns, see [Run bulk scans in
4543Docker](https://learn.chatgpt.com/docs/security/cli/bulk-scans#run-bulk-scans-in-docker).4658Docker](https://learn.chatgpt.com/docs/security/cli/bulk-scans#run-bulk-scans-in-docker).
4580 4695
4581#### Match and compare findings4696#### Match and compare findings
4582 4697
45834698Match findings that share the same root cause across two scans:Compare two scans to find new, persisting, reopened, resolved, and unknown
4699findings:
4584 4700
4585```bash4701```bash
45864702npx @openai/codex-security scans match PREVIOUS_SCAN_ID CURRENT_SCAN_IDnpx @openai/codex-security scans compare PREVIOUS_SCAN_ID CURRENT_SCAN_ID
4587```4703```
4588 4704
45894705Compare the matched scans to find new, persisting, reopened, resolved, andThe comparison automatically matches findings that share the same root cause
45904706unknown findings:and reuses saved matches. To save matches explicitly, use `scans match`:
4591 4707
4592```bash4708```bash
45934709npx @openai/codex-security scans compare PREVIOUS_SCAN_ID CURRENT_SCAN_IDnpx @openai/codex-security scans match PREVIOUS_SCAN_ID CURRENT_SCAN_ID
4594```4710```
4595 4711
4596A finding is unknown when the later scan has incomplete coverage or doesn't4712A finding is unknown when the later scan has incomplete coverage or doesn't
4782without writing the complete scan result to stdout. Request `--json`,4898without writing the complete scan result to stdout. Request `--json`,
4783`--format`, or `--full-output` to send structured scan results to stdout.4899`--format`, or `--full-output` to send structured scan results to stdout.
4784 4900
4901Interactive terminals show a live dashboard with the current scan phase,
4902reviewed files, activity, token usage, and estimated cost. CI and redirected
4903output use plain-text progress. Add `--headless` to use plain-text progress in
4904an interactive terminal:
4905
4906```bash
4907npx @openai/codex-security scan . --headless
4908```
4909
4785#### Verbose diagnostics4910#### Verbose diagnostics
4786 4911
4787Add `--verbose` to print redacted lifecycle, authentication, progress, and cost4912Add `--verbose` to print redacted lifecycle, authentication, progress, and cost
4901 5026
4902Set `OPENAI_API_KEY` or `CODEX_API_KEY`, sign in with5027Set `OPENAI_API_KEY` or `CODEX_API_KEY`, sign in with
4903`npx @openai/codex-security login`, or use an existing file-backed Codex5028`npx @openai/codex-security login`, or use an existing file-backed Codex
49045029sign-in. For Amazon Bedrock, use a Bedrock API key or the standard AWSsign-in. For OpenRouter or Fireworks, set the provider's API key and select a
5030model. For Amazon Bedrock, use a Bedrock API key or the standard AWS
4905credential chain instead.5031credential chain instead.
4906 5032
4907For credential selection, see [Select scan5033For credential selection, see [Select scan
4909 5035
4910For CI, keep the API key scoped to the scan step and use a trusted workflow.5036For CI, keep the API key scoped to the scan step and use a trusted workflow.
4911 5037
49125038The CLI requires Node.js 22 or later. Running a scan or exporting findings alsoThe CLI requires Node.js 22.13.0 or later. Running a scan or exporting findings
49135039requires Python 3.10 or later. Python 3.10 also requires `tomli`. Use `--python`also requires Python 3.10 or later. Python 3.10 also requires `tomli`. Use
49145040or `PYTHON` to select an interpreter when automatic discovery is unsuitable.`--python` or `PYTHON` to select an interpreter when automatic discovery is
5041unsuitable.
4915 5042
4916Continue with the [CLI quickstart](https://learn.chatgpt.com/docs/security/cli), [bulk-scan5043Continue with the [CLI quickstart](https://learn.chatgpt.com/docs/security/cli), [bulk-scan
4917guide](https://learn.chatgpt.com/docs/security/cli/bulk-scans), [CLI FAQ](https://learn.chatgpt.com/docs/security/cli/faq), [CI5044guide](https://learn.chatgpt.com/docs/security/cli/bulk-scans), [CLI FAQ](https://learn.chatgpt.com/docs/security/cli/faq), [CI
5586findings, coverage details, and paths to scan artifacts. For longer scans, it5713findings, coverage details, and paths to scan artifacts. For longer scans, it
5587supports preflight checks, cost limits, progress callbacks, and cancellation.5714supports preflight checks, cost limits, progress callbacks, and cancellation.
5588 5715
55895716The SDK uses ECMAScript modules (ESM) and runs server-side with Node.js 22 orThe SDK uses ECMAScript modules (ESM) and runs server-side with Node.js 22.13.0
55905717later. Scanning also requires Python 3.10 or later.or later. Scanning also requires Python 3.10 or later.
5591 5718
5592The Codex Security SDK is [publicly available on5719The Codex Security SDK is [publicly available on
5593GitHub](https://github.com/openai/codex-security). Running scans requires5720GitHub](https://github.com/openai/codex-security). Running scans requires
5604```5731```
5605 5732
5606Before starting a scan, set `OPENAI_API_KEY` or `CODEX_API_KEY`, use an5733Before starting a scan, set `OPENAI_API_KEY` or `CODEX_API_KEY`, use an
56075734existing file-backed Codex sign-in, or [configure Amazonexisting file-backed Codex sign-in, or [configure another
56085735Bedrock](#configure-the-runtime-and-credentials) with AWS credentials andprovider](#configure-the-runtime-and-credentials). Amazon Bedrock uses AWS
56095736explicit `model_provider` and `model` overrides.credentials; OpenRouter and Fireworks use provider-specific API keys and
5737configuration.
5610 5738
5611For best results, use an account verified for [Trusted Access for5739For best results, use an account verified for [Trusted Access for
5612Cyber](https://chatgpt.com/cyber). Signing in or providing an API key does not5740Cyber](https://chatgpt.com/cyber). Signing in or providing an API key does not
5646 5774
5647#### Check inputs with preflight5775#### Check inputs with preflight
5648 5776
56495777Use `preflight` to check a repository, target, mode, output location, andUse `preflight` to check a repository, target, mode, knowledge-base documents,
56505778Codex configuration before starting a scan:output location, and Codex configuration before starting a scan:
5651 5779
5652```ts5780```ts
5653const plan = await security.preflight("/path/to/repository", {5781const plan = await security.preflight("/path/to/repository", {
5654 target: ["services/billing", "packages/auth"],5782 target: ["services/billing", "packages/auth"],
5783 knowledgeBasePaths: ["/path/to/architecture.md"],
5655 outputDir: "/path/outside/repository/results",5784 outputDir: "/path/outside/repository/results",
5656});5785});
5657 5786
5752const result = await security.run("/path/to/repository", {5881const result = await security.run("/path/to/repository", {
5753 target: ["services/billing"],5882 target: ["services/billing"],
5754 mode: "deep",5883 mode: "deep",
5884 workers: 2,
5885 subagents: 0,
5886 stopAfterNoNew: 3,
5887 maxDiscoveryRuns: 10,
5755});5888});
5756```5889```
5757 5890
5758Deep mode supports repository and path targets. Use standard mode for diff and5891Deep mode supports repository and path targets. Use standard mode for diff and
57595892working-tree scans.working-tree scans. The optional settings control concurrent discovery workers,
5893subagents per worker, consecutive discovery runs without new findings, and the
5894total number of discovery runs. They require `mode: "deep"`.
5760 5895
5761#### Add a security knowledge base5896#### Add a security knowledge base
5762 5897
5777The SDK rejects linked input paths, skips linked directory entries, and keeps5912The SDK rejects linked input paths, skips linked directory entries, and keeps
5778extracted document content outside the saved scan results.5913extracted document content outside the saved scan results.
5779 5914
5915#### Add scan and follow-up instructions
5916
5917Use `scanPrompt` to focus the scan and `postScanPrompt` to request a follow-up
5918after a completed scan:
5919
5920```ts
5921const result = await security.run("/path/to/repository", {
5922 scanPrompt: "Focus on tenant isolation and authorization checks.",
5923 postScanPrompt: "Write confirmed findings to post-scan-summary.md.",
5924});
5925```
5926
5927The follow-up runs in the same authenticated session only after the scan
5928finishes with complete coverage.
5929
5780#### Set a scan budget5930#### Set a scan budget
5781 5931
5782Set `maxCostUsd` to stop a scan when its estimated model cost exceeds a limit.5932Set `maxCostUsd` to stop a scan when its estimated model cost exceeds a limit.
5793console.log(result.cost?.estimatedUsd);5943console.log(result.cost?.estimatedUsd);
5794```5944```
5795 5945
57965946The limit is an estimate, not a hard spending cap. Requests already in progressThe limit estimates spending but isn't a hard cap, so requests already in
57975947can finish above it. If the scan exceeds the limit, the SDK throwsprogress can finish slightly above it. If the scan exceeds the limit, the SDK
57985948`ScanCostLimitExceededError` and preserves the available results.throws `ScanCostLimitExceededError` and preserves the available results.
5799 5949
5800#### Work with scan results5950#### Work with scan results
5801 5951
5857 onScanStarted() {6007 onScanStarted() {
5858 console.log("Scan started");6008 console.log("Scan started");
5859 },6009 },
6010 onProgress(progress) {
6011 console.log(progress.phase, progress.filesCompleted, progress.filesTotal);
6012 },
5860 onWorkerStatus(status) {6013 onWorkerStatus(status) {
5861 console.log(status.kind, status);6014 console.log(status.kind, status);
5862 },6015 },
5903lifecycle callbacks:6056lifecycle callbacks:
5904 6057
5905| Callback | Called when |6058| Callback | Called when |
59066059| ----------------------------------- | ------------------------------------------------ || ----------------------------------- | ---------------------------------------------------- |
6060| `onAuthentication(authentication)` | The scan selects its authentication method. |
5907| `onOutputArchived(archiveDir)` | Existing results move to the archive directory. |6061| `onOutputArchived(archiveDir)` | Existing results move to the archive directory. |
5908| `onOutputDirReady(scanDir)` | The private scan directory is ready. |6062| `onOutputDirReady(scanDir)` | The private scan directory is ready. |
5909| `onScanStarted()` | Scan setup completes and execution begins. |6063| `onScanStarted()` | Scan setup completes and execution begins. |
6064| `onTrustedAccessStatus(status)` | Trusted Access status becomes available. |
5910| `onReconnect(attempt, maxAttempts)` | The SDK retries a disconnected scan stream. |6065| `onReconnect(attempt, maxAttempts)` | The SDK retries a disconnected scan stream. |
6066| `onActivity(activity)` | A command, tool, reasoning step, or message updates. |
6067| `onProgress(progress)` | The scan phase or reviewed file count changes. |
5911| `onWorkerStatus(status)` | Worker preflight or dispatch status changes. |6068| `onWorkerStatus(status)` | Worker preflight or dispatch status changes. |
5912| `onCost(cost)` | An updated estimated scan cost is available. |6069| `onCost(cost)` | An updated estimated scan cost is available. |
6070| `onWarning(warning)` | The scan reports a warning. |
5913| `onObserverError(observer, error)` | Another scan lifecycle callback raises an error. |6071| `onObserverError(observer, error)` | Another scan lifecycle callback raises an error. |
5914 6072
6073Trusted Access status is `granted`, `not_granted`, or `unknown`. Missing or
6074unknown access also triggers `onWarning`.
6075
5915#### Configure the runtime and credentials6076#### Configure the runtime and credentials
5916 6077
5917Pass runtime configuration when you need a specific plugin, interpreter, or6078Pass runtime configuration when you need a specific plugin, interpreter, or
5936Bedrock](https://learn.chatgpt.com/docs/security/cli/reference#use-amazon-bedrock), set6097Bedrock](https://learn.chatgpt.com/docs/security/cli/reference#use-amazon-bedrock), set
5937`model_provider` and `model` in `codexOverrides`.6098`model_provider` and `model` in `codexOverrides`.
5938 6099
6100For OpenRouter or Fireworks, also provide the matching API key and a complete
6101provider configuration in `codexOverrides`. For example, set
6102`OPENROUTER_API_KEY` and configure OpenRouter:
6103
6104```ts
6105const security = new CodexSecurity({
6106 codexOverrides: {
6107 model: "anthropic/claude-sonnet-4.5",
6108 model_provider: "openrouter",
6109 model_providers: {
6110 openrouter: {
6111 name: "OpenRouter",
6112 base_url: "https://openrouter.ai/api/v1",
6113 env_key: "OPENROUTER_API_KEY",
6114 wire_api: "responses",
6115 },
6116 },
6117 },
6118});
6119```
6120
6121For Fireworks, change both `openrouter` keys to `fireworks`, set `name` to
6122`Fireworks AI`, set `env_key` to `FIREWORKS_API_KEY`, use
6123`https://api.fireworks.ai/inference/v1` as `base_url`, and select a Fireworks
6124model.
6125
5939The client also exposes supported authentication methods:6126The client also exposes supported authentication methods:
5940 6127
5941| Method | Purpose |6128| Method | Purpose |
7020Create a CSV with one row for each repository and pinned revision:7207Create a CSV with one row for each repository and pinned revision:
7021 7208
7022```csv7209```csv
70237210id,repository,revision,scope,modeid,repository,revision,scope,mode,prompt
70247211payments,https://github.com/example/payments.git,0123456789abcdef0123456789abcdef01234567,services/api,standardpayments,https://github.com/example/payments.git,0123456789abcdef0123456789abcdef01234567,services/api,standard,Review payment authorization and refunds.
70257212identity,https://github.com/example/identity.git,fedcba9876543210fedcba9876543210fedcba98,,deepidentity,https://github.com/example/identity.git,fedcba9876543210fedcba9876543210fedcba98,,deep,Review session and identity boundaries.
7026```7213```
7027 7214
7028The CSV supports these columns:7215The CSV supports these columns:
7034| `revision` | Yes | Full 40- or 64-character Git commit SHA. Branch names, tags, and shortened commit hashes aren't supported. |7221| `revision` | Yes | Full 40- or 64-character Git commit SHA. Branch names, tags, and shortened commit hashes aren't supported. |
7035| `scope` | No | A repository-relative directory to scan. Omit the value to scan the full repository. |7222| `scope` | No | A repository-relative directory to scan. Omit the value to scan the full repository. |
7036| `mode` | No | `standard` or `deep`. Omit the value to use the command's selected mode. |7223| `mode` | No | `standard` or `deep`. Omit the value to use the command's selected mode. |
7224| `prompt` | No | Scan instructions specific to this repository. |
7037 7225
7038To find a local repository's full commit SHA, run:7226To find a local repository's full commit SHA, run:
7039 7227
7051 --workers 47239 --workers 4
7052```7240```
7053 7241
70547242`--workers` controls the number of concurrent repository scans and defaults to`--workers` controls concurrent repository scans and defaults to `4`. It does
70557243`4`. Use `--mode deep` to select deep scanning for rows without their ownnot set the number of discovery workers within each deep scan; configure those
70567244`mode`. Each CSV row can still choose its own scan mode and repository scope.limits through [`[deep_scan]`](/codex/security/cli/reference#configure-deep-scans).
7245Use `--mode deep` to select deep scanning for rows without their own `mode`.
7246Each CSV row can still choose its own scan mode and repository scope.
7057 7247
7058The CLI checks out each pinned revision, scans the selected target, records the7248The CLI checks out each pinned revision, scans the selected target, records the
7059result, and removes the temporary repository checkout. A repository counts as7249result, and removes the temporary repository checkout. A repository counts as
7060complete only when its scan has complete coverage and all required result7250complete only when its scan has complete coverage and all required result
7061artifacts exist.7251artifacts exist.
7062 7252
7253#### Share security context and instructions
7254
7255Add architecture documents, threat models, or security policies to every scan
7256with `--knowledge-base`. Repeat the flag for more files or directories:
7257
7258```bash
7259npx @openai/codex-security bulk-scan repositories.csv \
7260 --output-dir /path/outside/repositories/security-scans \
7261 --knowledge-base /path/to/architecture.md \
7262 --knowledge-base /path/to/security-policies
7263```
7264
7265To add shared scan instructions or run a follow-up after each completed scan,
7266provide prompt files:
7267
7268```bash
7269npx @openai/codex-security bulk-scan repositories.csv \
7270 --output-dir /path/outside/repositories/security-scans \
7271 --scan-prompt-file scan-instructions.md \
7272 --post-scan-prompt-file follow-up.md
7273```
7274
7275The CLI appends each repository's CSV `prompt` after the shared scan
7276instructions. Follow-up instructions run in the same authenticated session only
7277after a validated scan has complete coverage. Prompt file paths resolve from
7278your current directory.
7279
7063#### Choose a model and reasoning effort7280#### Choose a model and reasoning effort
7064 7281
7065Bulk scans use `gpt-5.6-sol` with `xhigh` reasoning effort by default. To7282Bulk scans use `gpt-5.6-sol` with `xhigh` reasoning effort by default. To
7081 7298
7082Supported effort levels are `minimal`, `low`, `medium`, `high`, and `xhigh`.7299Supported effort levels are `minimal`, `low`, `medium`, `high`, and `xhigh`.
7083 7300
7301To use OpenRouter or Fireworks, set `OPENROUTER_API_KEY` or `FIREWORKS_API_KEY`,
7302respectively, and specify `--provider` and `--model`. For credentials and
7303examples, see [OpenRouter or Fireworks
7304setup](https://learn.chatgpt.com/docs/security/cli/reference#use-openrouter-or-fireworks) or [Amazon
7305Bedrock setup](https://learn.chatgpt.com/docs/security/cli/reference#use-amazon-bedrock).
7306
7084#### Review campaign results7307#### Review campaign results
7085 7308
7086The output directory contains the pinned campaign, an append-only results7309The output directory contains the pinned campaign, an append-only results
7106 └── report.md7329 └── report.md
7107```7330```
7108 7331
71097332- `manifest.json` records the repositories, pinned revisions, scopes, and scan- `manifest.json` records the repositories, pinned revisions, scopes, scan
71107333 modes in the campaign. modes, and shared or repository-specific instructions in the campaign.
7111- `results.jsonl` records each repository attempt, its status, artifact7334- `results.jsonl` records each repository attempt, its status, artifact
7112 directory, and any available cost or error details.7335 directory, and any available cost or error details.
7113- `report.md` provides a readable report for one repository attempt.7336- `report.md` provides a readable report for one repository attempt.
7137 --workers 47360 --workers 4
7138```7361```
7139 7362
71407363The CLI resumes repositories that still need work. It skips a completedThe CLI resumes unfinished repository scans and skips completed ones. Scans
71417364repository only when the corresponding receipt and all required scan artifactswith incomplete coverage aren't retried. Their results remain available, and
71427365still exist.the command exits with code `2`.
7143 7366
71447367Don't change the repository inventory for an existing output directory. The CLIDon't change the repository inventory or scan and follow-up instructions for
71457368checks the pinned manifest and rejects a different campaign. Use a new outputan existing output directory. The CLI checks the pinned manifest and rejects a
71467369directory when you change repositories, revisions, scopes, or scan modes.different campaign. Use a new output directory when you change repositories,
7370revisions, scopes, scan modes, or shared or repository-specific instructions.
7147 7371
7148#### Retry repository errors7372#### Retry repository errors
7149 7373
7158```7382```
7159 7383
7160The default is one attempt per repository. Every attempt receives its own7384The default is one attempt per repository. Every attempt receives its own
71617385receipt and artifact directory.receipt and artifact directory. Retries cover checkout errors, scan failures,
7386and missing required artifacts. Completed scans with incomplete coverage
7387aren't retried.
7162 7388
7163Bulk scans use these exit codes:7389Bulk scans use these exit codes:
7164 7390
7224 7450
7225The runner needs:7451The runner needs:
7226 7452
72277453- Node.js 22 or later.- Node.js 22.13.0 or later.
7228- Python 3.10 or later.7454- Python 3.10 or later.
7229- The published `@openai/codex-security` package, installed outside the7455- The published `@openai/codex-security` package, installed outside the
7230 repository checkout.7456 repository checkout.