🤖 fix: redact MCP command env values and credential URLs in settings backup export - #3985
🤖 fix: redact MCP command env values and credential URLs in settings backup export#3985ibetitsmike wants to merge 107 commits into
Conversation
…ckup export The export projection treated 'command' and 'url' as fully portable strings, so env-style credentials embedded in a command (FOO_TOKEN=... cmd) and credentials inside URLs were published verbatim with an empty mcpRedactions. Redact assignment values in command strings (object and bare-string servers), redact credential-bearing URLs whole-value, and record both in the manifest so restore rehydrates them from the local config. Manifest sha256 stays computed over the redacted bytes as written. Defense in depth: createBackupPayload now hard-fails when a known credential token format survives in the finished payload, with no approval override; the local safety snapshot stays exempt. The Settings UI hides the secret-scan override for blocks that carry no approval digest.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cbfabe752e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
This comment has been minimized.
This comment has been minimized.
…ted URLs on restore
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7c2d5ad4be
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Security Review
Here are some automated security review suggestions for this pull request.
Reviewed commit: 7c2d5ad4be
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
…on quote-led assignments
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 543d699c8f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 543d699c8f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
This comment has been minimized.
This comment has been minimized.
…, process substitution fail-closed
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 875b0c8c82
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
This comment has been minimized.
This comment has been minimized.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b9f9f51be0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Security Review
Here are some automated security review suggestions for this pull request.
Reviewed commit: b9f9f51be0
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9fd948f88e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Security Review
Here are some automated security review suggestions for this pull request.
Reviewed commit: 9fd948f88e
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
|
@codex review |
This comment has been minimized.
This comment has been minimized.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 19c9cddf44
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…Python under PYTHONSTARTUP
|
@codex review |
This comment has been minimized.
This comment has been minimized.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8cfe2e0a2d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 733a118b58
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Security Review
Here are some automated security review suggestions for this pull request.
Reviewed commit: 733a118b58
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a1ff70a324
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
This comment has been minimized.
This comment has been minimized.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Security Review
Here are some automated security review suggestions for this pull request.
Reviewed commit: 909a7444bc
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 909a7444bc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
This comment has been minimized.
This comment has been minimized.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4e44d8272a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ives, and git -c overrides
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c66a998ede
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| for (const dir of searchDirs) { | ||
| if (dir !== "" && isAutoPublishedScriptOperand(`${dir}/${entry}`, rootPrefixes)) { |
There was a problem hiding this comment.
Canonicalize loader search directories before matching
When an inherited loader search directory is a symlink into the collected root, such as LD_LIBRARY_PATH=/opt/xum-lib with /opt/xum-lib -> <root>/skills and LD_PRELOAD=launch.txt, this lexical join misses the automatically published library. Fresh evidence beyond the direct loader-path fix is that the installed ld.so --help documents --library-path as the replacement for LD_LIBRARY_PATH and --preload as loading named objects; I reproduced the symlink spelling loading a shared object named launch.txt, while LocalBaseRuntime.ts:91 preserves these variables. Canonicalize existing loader search directories before checking the joined preload name.
Useful? React with 👍 / 👎.
| pythonPathHook: (process.env.PYTHONPATH ?? "") | ||
| .split(path.delimiter) | ||
| .some((entry) => isAutoPublishedScriptOperand(entry, rootPrefixes)), |
There was a problem hiding this comment.
Canonicalize inherited PYTHONPATH archive entries
When PYTHONPATH names a symlink to an automatically published archive, for example /opt/archive -> <root>/skills/launch.txt, this lexical test leaves an approved python3 -m leak command publishable even though Python imports leak from the collected archive. Fresh evidence beyond the resolved direct-PYTHONPATH case is a local reproduction through that symlink; python3 --help-env documents PYTHONPATH as entries prepended to the module search path, and LocalBaseRuntime.ts:91 preserves the variable. Resolve existing entries with realpath before deciding whether the Python launcher must remain local.
Useful? React with 👍 / 👎.
| } else if (pendingSqliteOptions && unquoted === "-init") { | ||
| pendingSqliteInitFile = true; |
There was a problem hiding this comment.
Localize sqlite3 command options
When an approved launcher uses sqlite3 -cmd '.shell …' :memory:, this state recognizes only -init, although the installed sqlite3 --help documents -cmd COMMAND as running the command before stdin. I reproduced a quoted .shell operand passing ghp_Abcdef1234\Klmno567890123456 through a second shell parse as the contiguous token; the outer shell-normalized backstop retains the backslash inside the quoted SQLite operand, so the command remains publishable. Treat -cmd and its following operand as executable input rather than scanning only init files.
Useful? React with 👍 / 👎.
| for (const match of value.matchAll(SHELL_WORD)) { | ||
| const option = unquoteShellWord(match[0]); | ||
| const agent = /^-(?:javaagent|agentpath):([^=]+)/.exec(option)?.[1]; | ||
| if (agent !== undefined && isAutoPublishedScriptOperand(agent, rootPrefixes)) return true; |
There was a problem hiding this comment.
Inspect inherited Java boot class paths
When JAVA_TOOL_OPTIONS=-Xbootclasspath/a:<root>/skills/launch.txt, a plain approved command such as java Leak loads executable classes from the automatically published archive, but this inherited-option scan recognizes only agents. Fresh evidence beyond the handled agent and CLASSPATH cases is that the installed java --help-extra documents -Xbootclasspath/a as accepting directories and zip/JAR files, and I reproduced a JAR renamed to .txt supplying and executing the main class through JAVA_TOOL_OPTIONS. Detect published boot-class-path archives in the inherited JVM option variables before allowing Java launchers to remain portable.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Security Review
Here are some automated security review suggestions for this pull request.
Reviewed commit: c66a998ede
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
|
|
||
| /** Java class-path options whose value may itself be an executable archive. */ | ||
| function isJavaClassPathOption(unquoted: string): boolean { | ||
| return /^(?:-cp|-classpath|--class-path)$/.test(unquoted); |
There was a problem hiding this comment.
Security: Localize Java boot-class-path archives
Requires Java, a user-approved MCP export, an automatically published .txt archive, and a backup readable by a lower-trust party. This allowlist misses -Xbootclasspath/a:<path>: OpenJDK 25 executed Leak from <root>/skills/launch.txt despite the .txt suffix, while the exporter treats that option as opaque and keeps the command portable. The reproduced archive stored a GitHub-token-shaped value in separate constants, so the raw-file backstop saw no contiguous token although Java reconstructed it. Localize direct and inherited boot-class-path archives.
Useful? React with 👍 / 👎.
Summary
Settings backup export published MCP server
commandstrings andurlvalues verbatim, so inline credentials (env-style assignments in commands, tokens in URLs) could leak into backup repositories once the user approved the secret-scan digest formcp.jsonc. This PR redacts those values at export time and adds a non-overridable credential-format backstop on the finished payload.Background
The exporter always classified
commandandurlas fully-portable strings (an old test asserted "keeps MCP commands and URLs ... verbatim"), relying on the digest-approvable secret scan instead. Once a user approved the flaggedmcp.jsonc, inline tokens published verbatim withmcpRedactions: []. The restore machinery already supported redacted command rehydration, so the export side and a URL-marker restore gap were the missing pieces.Implementation
redactMcpConfigreplaces everyNAME=valueassignment value in command strings (object and bare-string servers) with__MUX_BACKUP_REDACTED__. The value grammar consumes a whole shell word (escapes and quoted segments included), and assignments are recognized at start-of-string, whitespace, and shell word breaks (;,&,|,<,>,(,),{,}, backquote). When boundaries cannot be trusted, the whole command is replaced by the marker instead: unconsumable values (unterminated quote, trailing backslash), words that shell quote removal turns intoNAME=valueassignments forenv/eval-style consumers (TOKEN\=x,'TOKEN'=x,"TOKEN=a b"), or expansion syntax ($(),${}, backticks,<(,>() around an assignment.mcpRedactions. Restore rehydrates each marker from the local config at the same path; without a local value,resolveRestoredUrls(mirroring the command resolution) drops a marker url when the entry keeps a usable command — the command approval gate covers the now-runnable stdio fallback — and removes the server otherwise, so a marker can never survive as a connectable endpoint or executable command. Restore bookkeeping keys resolved paths with the JSON path encoder, so crafted server names containing delimiter characters cannot shadow another entry's resolution.createBackupPayloadhard-fails (BackupCredentialDetectedError, codeSECRET_DETECTED, no approval digest) when a known credential format (glsa_,ghp_,gho_,github_pat_,sk-,lin_api_,ntn_,xox[baprs]-,AKIA…) survives anywhere in the finished payload. Local safety snapshots (keepLocalSecrets) stay exempt since they never leave the machine.Validation
Red-green verified with independent toggles: removing command redaction, reverting the shell-word grammar, reverting operator boundaries, disabling the fail-closed fallbacks, removing URL redaction, unwiring the URL restore resolver, and unwiring the backstop each fail exactly the guarding tests.
Risks
ghp_token in AGENTS.md) is now a hard export block instead of an approvable finding. Intentional, but users who previously approved such content will see exports fail until they remove the credential.NAME=valueassignment value becomes machine-local, and commands with untrustworthy word boundaries (quote-led assignments, expansions around assignments) go local as a whole, requiring rehydration on restore.Generated with
xum• Model:anthropic:claude-fable-5• Thinking:xhigh