openai / openai/codex-plugin-cc
Focus text in adversarial-review is re-tokenized; --FLAG VALUE substrings leak into CLI args
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 33.3k
- Forks
- 2.3k
- PR merge metrics
- No merged PRs in 30d
Description
Summary
When /codex:adversarial-review (or the underlying node scripts/codex-companion.mjs adversarial-review …) is invoked with a focus text argument, the focus text is re-tokenized by normalizeArgv + splitRawArgumentString. Any literal --FLAG VALUE substring inside the focus text is then consumed by the option parser and forwarded as if the caller had set that flag — including --model X, which gets sent to the OpenAI API as the model selection.
The result is a 400 from the OpenAI API:
{"type":"error","status":400,"error":{"type":"invalid_request_error","message":"The 'pm_v6_2' model is not supported when using Codex with a ChatGPT account."}}
Reproduced on plugin version 1.0.3 and verified by reading origin/main (1.0.4) — the bug is still present upstream.
Reproduction
node ~/.claude/plugins/cache/openai-codex/codex/1.0.3/scripts/codex-companion.mjs \
adversarial-review "Review the build script. The build command is: build_v6_artifact.py --variant v6.2 --model pm_v6_2"
Expected: review runs, focus text is treated as opaque prose.
Actual: companion picks pm_v6_2 as the model, OpenAI rejects it as an unknown model name.
Any focus text that mentions a flag-with-value example (which is common for design reviews of CLI tools) hits this. Using a placeholder like <registry_name> also fails (The '<registry_name>' model is not supported).
Root cause
scripts/lib/args.mjs:
splitRawArgumentString(raw)does a shell-like tokenization of a single string into argv-style tokens.
scripts/codex-companion.mjs:
normalizeArgv(argv)(line 127-134) callssplitRawArgumentStringwhenargv.length === 1.main()(line 980-988) destructures:const [subcommand, ...argv] = process.argv.slice(2);. When the caller passes a single quoted focus argument,argvhas exactly one element —normalizeArgvthen re-tokenizes the user's whole focus prose.handleReviewCommand(line 683-687) usesparseCommandInputwithvalueOptions: ["base", "scope", "model", "cwd"]andaliasMap { m: "model" }. Any--model XXX(or-m XXX) substring in the re-tokenized prose is consumed as the OpenAI model selection. The remaining tokens become positionals (focus text), so the visible failure mode is "review runs against the wrong model name" rather than "command rejected with a syntax error".
The same vulnerability applies to --base, --scope, --cwd, --effort, --prompt-file, etc., wherever the corresponding subcommand registers them as value options. --model happens to be the most visible one because the OpenAI API returns an explicit error.
Suggested fix directions
Several options, in increasing strictness:
- Stop re-tokenizing focus text. Treat positionals after the subcommand as opaque — don't run
splitRawArgumentStringon them. Callers who want CLI options in the same call must pass them as separate argv elements. This is what most Unix tools do (grep "--FLAG value"does not parse the quoted string). - Tokenize only the option-prefix portion of argv. Stop tokenizing as soon as the parser sees a non-option positional. Concretely: split the raw string, then on the first non-
-token, glue all remaining tokens back into a single positional. This preserves thenode companion.mjs review --background "focus"ergonomics without leaking flags from inside"focus". - Require an explicit
--separator before focus text when the caller wants opaque content. Documentnode companion.mjs adversarial-review --background -- "focus text". This is the lowest-risk change but pushes burden onto callers. - Reject
--model(and similar) embedded in focus text at thevalidateNativeReviewRequest/handleReviewCommandlayer when both a positional--modeltoken and a focus body are present. Hostile but explicit.
Option 1 or 2 seems right: focus text should never silently become CLI options.
Impact
- Affects any review where the focus text contains a CLI example involving
--model,--base,--scope,--effortetc. Very common when reviewing CLI tooling, model-deploy scripts, or anything that takes a--modelflag. - Workaround: rewrite the focus prose to avoid literal
--FLAG VALUEpatterns. Discoverable only by reading the companion source.
Environment
- Plugin:
openai-codexv1.0.3 (also confirmed present onorigin/mainat v1.0.4) - Claude Code on macOS (darwin 25.4.0)
- ChatGPT account auth (the surfaced error is account-tier specific, but the root cause is general)
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with scripts/codex-companion.mjs, tracing normalizeArgv, main(), and handleReviewCommand(), then inspect splitRawArgumentString in scripts/lib/args.mjs. Re-run the adversarial-review example from the issue and verify that --model and other flag-like text in the focus argument remain opaque while genuine options still work. No test file is named in the issue.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 64/100