Codex Security: recoverable finalization schema error permanently fails completed scan

Open 💬 2 comments Opened Aug 8, 2026 by caseypettingill

Summary

A Codex Security diff scan completed discovery, validation, attack-path analysis, and canonical draft generation, but finalization rejected an empty scan.target.snapshotDigest. After repairing the digest in a fresh turn, completion could not be retried because the first validation error had already moved the scan into the terminal failed state.

This makes a recoverable metadata/schema error permanently prevent sealing an otherwise completed long-running scan.

Environment

  • Codex desktop on Windows with Ubuntu/WSL 2
  • Codex Security plugin: 0.1.17 when the scan began; 0.1.18 subsequently installed
  • Scan mode: Git revision-range/diff scan
  • Exact base and head revisions were available throughout
  • Repository checkout remained unchanged

Private scan identifiers and unsealed artifacts can be provided privately if needed.

Reproduction

  1. Start a Codex Security diff scan over an exact base/head revision range.
  2. Complete all review receipts and the validation and attack-path phases.
  3. Author the canonical unsealed draft artifacts.
  4. Call scan completion.
  5. Completion fails with:

``
scan.target.snapshotDigest: expected a non-empty string
``

  1. In a fresh turn, populate the correct deterministic snapshot digest and verify the canonical artifacts.
  2. Call completion once more.
  3. Completion fails with:

``
Only a running scan can be completed.
``

The first finalization validation error has already marked the scan failed, and the exposed workflow has no supported failed → running recovery transition.

Expected behavior

One or more of the following:

  • Populate and validate snapshotDigest before attempting terminal finalization.
  • Treat canonical artifact/schema validation errors as recoverable and leave the scan running.
  • Make finalization transactional so a validation failure does not persist terminal state.
  • Provide an audited recovery/reopen operation for scans whose artifacts are repaired after a finalization error.

Actual behavior

The expensive analytical phases and valid draft artifacts remain available, but the scan cannot be sealed or displayed as completed. The only supported alternative appears to be rerunning the entire scan.

Additional context

The installed 0.1.18 package documents snapshotDigest as required for Git diff targets, but includes no recovery procedure for this terminal state. The public Codex Security changelog currently stops at 0.1.17.

No repository contents, finding details, local paths, scan identifiers, or sensitive artifacts are included in this issue.

View original on GitHub ↗

2 Comments

4Liberty · 19 days ago

Additional 0.1.18 root-cause evidence: this is not limited to a stale draft from 0.1.17. I reproduced the same terminal failure on three distinct 0.1.18 Git diff scans (both commit and range). In the packaged workbench, require_diff_target computes and returns contentDigest only for working_tree; the commit and range branches return only kind/base/head. workbench_completion_binding likewise writes snapshotDigest only when the target kind is working_tree, while the final report schema requires a non-empty scan.target.snapshotDigest for every git_diff. That leaves a required identity field to model-authored artifact text, which is brittle and can place a digest in narrative context without populating the structured target field. The finalizer then calls the terminal failure transition on the resulting contract error.\n\nA durable upstream fix should (1) compute and persist a workbench-owned digest for commit/range targets from the exact resolved base/head Git diff, (2) inject and independently verify that digest during finalization instead of asking the model to reproduce it, and (3) keep contract/schema assembly errors in running so the same scan can correct and retry. No private repository data or scan identifiers are needed to reproduce this control-flow mismatch.

nos1609 · 15 days ago

Independent reproduction on Linux / VS Code Web with the Codex Security 0.1.18 runtime.

Environment:

  • Codex CLI 0.147.0
  • Codex extension 26.803.61601 (linux-x64)
  • VS Code Web remote extension host, Firefox client
  • Git diff target: range
  • Thread ID for internal trace lookup: 019f43ac-20b8-7ad1-965b-3b2e6460255d

Observed:

  1. The scan completed its substantive work and reached reporting 3/3 report_artifacts, with preflight complete.
  2. complete_codex_security_scan returned:

``
Codex Security scan completion failed.
scan.target.snapshotDigest: expected a non-empty string
``

  1. Scan context immediately reported terminal status: failed, the same failureMessage, and no report.
  2. In a fresh turn, the deterministic digest for the exact range was computed and added to the unsealed manifest. Completion still could not be retried because the scan had already left running:

``
Only a running scan can be completed.
``

Inspection of the packaged 0.1.18 runtime matches the root cause described above: a range target is persisted as kind/base/head without a workbench-owned content digest; the completion binding does not inject snapshotDigest for that target kind; the final report contract requires it for git_diff; and the contract failure is persisted as terminal failed.

This independently confirms two defects still present in 0.1.18 and shows they are not Windows-specific:

  1. Missing digest generation/binding for range diff targets.
  2. Non-transactional finalization that makes a repairable schema error unrecoverable.

Expected behavior:

  • Compute and persist the digest from the resolved range before finalization.
  • Keep the scan running on schema/contract assembly errors, or expose an audited retry/reopen operation.
  • Allow completion to be retried idempotently after metadata repair without rerunning the completed scan work.

No repository contents, local paths, revisions, scan IDs, artifacts, request IDs, or account data are included.

Follow-up: byte-identical working_tree workaround succeeds

I completed the same review with Codex Security 0.1.18 by changing only the target representation:

  1. Created a temporary detached worktree at the original range base.
  2. Applied the exact base-to-head binary diff as a working-tree patch.
  3. Verified that the resulting diff bytes were identical to the original range and computed the plugin's deterministic working-tree content digest.
  4. Started a replacement diff scan with target kind working_tree and that workbench-owned contentDigest.

The replacement scan then behaved correctly:

  • the unsealed manifest received scan.target.snapshotDigest automatically;
  • finalization succeeded;
  • the canonical artifacts were sealed and report.md was generated.

The original range scan remained terminally failed and could not be repaired or resumed.

This isolates the defect further: identical reviewed bytes succeed through the working_tree metadata path and fail through the range metadata path. The content and canonical findings are not the cause. The difference is that the working-tree path computes, persists, and injects its content digest, while the range path does not.

The workaround is not a practical recovery mechanism because it requires a replacement scan and re-execution of the scan workflow. It does, however, provide a deterministic regression test for an upstream fix: equivalent range and working_tree targets should both receive workbench-owned snapshot identity and should both finalize successfully.