Summary
Every scan --diff run fails at the save step with:
Could not save the Codex Security scan: scan.target.snapshotDigest: expected a non-empty string
The scan itself completes successfully — the agent reviews the diff, builds a threat model, and writes scan-manifest.json, findings.json, and coverage.json. Only the final save is rejected, so the entire scan is discarded and the CLI exits 2.
The cause appears to be a schema mismatch inside the tool: for target.kind: "git_diff" the plugin writes a target block with no snapshotDigest field, but the save-side validator requires one.
Repository scans (no --diff) are unaffected and save normally.
Reproduction
Minimal, self-contained — a one-file repository with two commits:
mkdir -p /tmp/probe && cd /tmp/probe
git init -q && git config user.email a@b.c && git config user.name p
echo base > app.txt && git add -A && git commit -qm base
echo changed > app.txt && git add -A && git commit -qm change
npx --yes @openai/codex-security@0.1.7 scan . \
--auth chatgpt \
--model gpt-5.6-luna \
--effort high \
--max-cost 0.50 \
--diff HEAD~1 \
--output-dir /tmp/out \
--verbose
Result:
[07:04] Running scan: building threat model (committed changes) | Files: 1/1
codex-security: debug: scan.failed classification="unknown" partial_output=true
Could not save the Codex Security scan: scan.target.snapshotDigest: expected a non-empty string
Partial output was kept at /tmp/out.
Removing --diff from the same command makes it succeed and print Scan complete.
Evidence
The preserved scan-manifest.json shows status: "completed" with all required artifacts present, and a target block with no snapshotDigest:
{
"documentType": "codex-security.scan-manifest",
"schemaVersion": "1.0",
"scan": {
"status": "completed",
"producer": { "name": "codex-security-plugin", "version": "0.1.15" },
"target": {
"kind": "git_diff",
"targetId": "target_sha256_ce9ecd19952d3cad45e46f75d207a5e82504efa390915e0e6c1e4bffea06e5cc",
"displayName": "probe2",
"baseRevision": "ac0c1def281595d9aeedf404af43602841724901",
"headRevision": "975a26fc600c85942a1f9d648b902602d7f138e9"
}
}
}
findings.json, coverage.json, threat_model.md and the full artifacts/ tree are all written. On a real 12-file diff the same run produced three well-formed medium-severity findings before being discarded by the same error.
Affected versions
| Version |
--diff |
repository scan |
| 0.1.7 |
fails |
succeeds |
| 0.1.6 |
fails |
not retested |
Not a regression in 0.1.7 — 0.1.6 fails identically.
Impact
--diff is the natural mode for CI, where the point is scanning a pull request's changes rather than the whole tree. Falling back to a full repository scan is not a practical workaround: on a 3,600-file repository the diff scan of 12 files already took 27 minutes, so scanning everything per PR is out of reach.
Because the scan runs to completion before failing, each attempt costs full time and tokens and returns nothing.
Environment
@openai/codex-security 0.1.7 and 0.1.6, bundled plugin 0.1.15
codex 0.144.6, codex-sdk 0.144.6
- Node 22, Ubuntu 24.04 container, x86-64
- Auth:
--auth chatgpt
- Reproduced identically on a self-hosted GitHub Actions runner and in a bare
docker run
Possibly related
In a container, the scan agent's sandbox cannot initialize, and the agent reports internally: "the terminal wrapper is unavailable in this host because its sandbox namespace cannot initialize". It then silently proceeds without a shell and fails much earlier with Scan agent did not create required draft artifacts: scan-manifest.json, findings.json, coverage.json.
Running the container with --security-opt seccomp=unconfined resolves that and lets the agent work normally. It may be worth surfacing a clearer diagnostic for that case, since the current message points at the scan directory rather than at sandbox initialization.
Summary
Every
scan --diffrun fails at the save step with:The scan itself completes successfully — the agent reviews the diff, builds a threat model, and writes
scan-manifest.json,findings.json, andcoverage.json. Only the final save is rejected, so the entire scan is discarded and the CLI exits 2.The cause appears to be a schema mismatch inside the tool: for
target.kind: "git_diff"the plugin writes a target block with nosnapshotDigestfield, but the save-side validator requires one.Repository scans (no
--diff) are unaffected and save normally.Reproduction
Minimal, self-contained — a one-file repository with two commits:
Result:
Removing
--difffrom the same command makes it succeed and printScan complete.Evidence
The preserved
scan-manifest.jsonshowsstatus: "completed"with all required artifacts present, and a target block with nosnapshotDigest:{ "documentType": "codex-security.scan-manifest", "schemaVersion": "1.0", "scan": { "status": "completed", "producer": { "name": "codex-security-plugin", "version": "0.1.15" }, "target": { "kind": "git_diff", "targetId": "target_sha256_ce9ecd19952d3cad45e46f75d207a5e82504efa390915e0e6c1e4bffea06e5cc", "displayName": "probe2", "baseRevision": "ac0c1def281595d9aeedf404af43602841724901", "headRevision": "975a26fc600c85942a1f9d648b902602d7f138e9" } } }findings.json,coverage.json,threat_model.mdand the fullartifacts/tree are all written. On a real 12-file diff the same run produced three well-formed medium-severity findings before being discarded by the same error.Affected versions
--diffNot a regression in 0.1.7 — 0.1.6 fails identically.
Impact
--diffis the natural mode for CI, where the point is scanning a pull request's changes rather than the whole tree. Falling back to a full repository scan is not a practical workaround: on a 3,600-file repository the diff scan of 12 files already took 27 minutes, so scanning everything per PR is out of reach.Because the scan runs to completion before failing, each attempt costs full time and tokens and returns nothing.
Environment
@openai/codex-security0.1.7 and 0.1.6, bundled plugin 0.1.15codex0.144.6,codex-sdk0.144.6--auth chatgptdocker runPossibly related
In a container, the scan agent's sandbox cannot initialize, and the agent reports internally: "the terminal wrapper is unavailable in this host because its sandbox namespace cannot initialize". It then silently proceeds without a shell and fails much earlier with
Scan agent did not create required draft artifacts: scan-manifest.json, findings.json, coverage.json.Running the container with
--security-opt seccomp=unconfinedresolves that and lets the agent work normally. It may be worth surfacing a clearer diagnostic for that case, since the current message points at the scan directory rather than at sandbox initialization.