Skip to content

Deep scans pass literal $CODEX_SECURITY_SCAN_ID to MCP, causing Invalid UUID and missing artifacts #290

Description

@ECHOQWETVG

Summary

With @openai/codex-security@0.1.7, a deep scan can fail before discovery because the generated agent prompt tells the agent to call the MCP tool with the literal string "$CODEX_SECURITY_SCAN_ID" as scanId.

The agent follows that instruction literally in the MCP JSON argument. Environment-variable expansion does not occur in JSON tool arguments, so the workbench rejects it as an invalid UUID. The CLI then reports only the secondary missing-artifacts error, which makes this look like a shell/filesystem permission problem.

Reproduction

Run a deep scan from a clean detached worktree, with the output directory outside the worktree:

git worktree add --detach ../repo-codex-scan HEAD

codex-security scan ../repo-codex-scan \
  --auth chatgpt \
  --effort high \
  --mode deep \
  --output-dir /tmp/codex-security-output

In the Codex session transcript, the first deep-scan MCP call is equivalent to:

start_codex_security_deep_scan({"scanId":"$CODEX_SECURITY_SCAN_ID"})

The MCP server responds:

MCP error -32602: Invalid UUID

The agent then stops, and finalization surfaces only:

Could not save the Codex Security scan: Scan agent did not create required draft artifacts:
scan-manifest.json, findings.json, coverage.json.

Expected behavior

The SDK should pass the registered scan's actual UUID to the agent/MCP call, for example:

{"scanId":"c690abe8-fe02-474a-9394-8c7920d3e127"}

If initialization fails, the CLI should also preserve the Invalid UUID MCP error as the primary diagnostic rather than replacing it with the downstream missing-artifacts error.

Root cause

The current source prompt contains:

'The SDK has already registered this scan. Call start_codex_security_deep_scan with { scanId: "$CODEX_SECURITY_SCAN_ID" }; never pass targetPath or create another scan.'

Source on current main:
https://github.com/openai/codex-security/blob/442e5936a217978272fe4b5ff03468e821af4908/sdk/typescript/src/api.ts

This syntax would be expanded by a shell command, but the instructed operation is a structured MCP call. The model therefore sends the string beginning with $ exactly as written.

Suggested fix

After registration, interpolate the already-known scanId into the deep-scan prompt before starting the Codex thread. Alternatively, pass scanId into scanPrompt() and render the UUID there.

A local workaround that replaced the literal placeholder in basePrompt with the registered scanId allowed initialization to proceed. One detail: when false-positive feedback is present, the feedback branch must append to the corrected prompt rather than resetting it back to basePrompt.

It would also help to propagate initialization MCP failures through finalization so that a concrete Invalid UUID error is not masked by the generic required-draft-artifacts check.

Environment

  • @openai/codex-security@0.1.7
  • Bundled plugin: 0.1.15
  • Authentication: --auth chatgpt
  • Mode: --mode deep
  • Node.js: v24.13.0
  • macOS: 26.5.2
  • Clean detached Git worktree
  • Output directory outside the scanned worktree

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions