Skip to content

feat(scanner): reject plugin secrets copied into MCP env and args - #1161

Draft
seonghobae wants to merge 10 commits into
feat/claude-plugin-secret-to-prompt-1099from
feat/claude-plugin-secret-to-mcp-1099
Draft

seonghobae wants to merge 10 commits into
feat/claude-plugin-secret-to-prompt-1099from
feat/claude-plugin-secret-to-mcp-1099

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 7, 2026 •

Copy link
Copy Markdown
Contributor

Current repair boundary — 2026-09-12

Successor of #1158 / issue #1099. Does not Close those. Does not steal #1158 secret-to-prompt, #1137 secret-to-network, #1157 conflicting-identity, or G-06 #1152.

Unique delta and authoritative boundary

Fail closed when an actual named-secret reference is copied into a Claude Code MCP server execution field (claude-plugin-secret-to-mcp).

Claude Code's current MCP contract expands environment references in command, args, env, url, and headers:
https://code.claude.com/docs/en/mcp

  • .mcp.json env.OPENAI_API_KEY=$OPENAI_API_KEY fails admission.
  • MCP args: ["--token", "$GITHUB_TOKEN"] and command interpolation fail admission.
  • Remote MCP URL and header references such as ${OPENAI_API_KEY} fail admission.
  • Exact env key names remain fail closed.
  • Plain documentation such as --help=configure OPENAI_API_KEY, printf OPENAI_API_KEY, and longer names such as OPENAI_API_KEY_DOCUMENTATION are not secret copies.
  • Exact supported default expansion such as ${OPENAI_API_KEY:-} remains positive.
  • A bounded MCP without secret flow is not this finding.
  • Curl secret copies remain feat(scanner): reject GitHub write tokens and Docker sockets #1137 claude-plugin-secret-to-network; prompt/log copies remain feat(scanner): reject plugin secret-to-prompt and secret-to-log flows #1158 claude-plugin-secret-to-prompt.
  • README prose is not a manifest. Snippets contain only the env name and omit secret values and bidi.

Ordinary restack and TDD lineage

  • Merge ab73726c1bf96041b06b38ca1efed83d56e7a749 has prior feat(scanner): reject plugin secrets copied into MCP env and args #1161 a92e936f... as first parent and current feat(scanner): reject plugin secret-to-prompt and secret-to-log flows #1158 29d4214c... as second parent. Its tree 1f575315... matches the independently verified local merge tree.
  • FP RED 172c260d52b8bc3a9a608e7405816127d20eefba: 3 failed / 9 deselected for prose-only args/command and near-name env keys.
  • FP GREEN 9303bfe414609a2826bd76a6a15961a231090900: existing positives plus 12/12 module and 232/232 Claude-plugin-family tests passed.
  • Surface FN RED 89cc8c33e793a4aef7b4f5ffc3e5023f9545ef0c: 2 failed / 12 deselected for URL/header references.
  • Surface GREEN 9d4c2cf015484e841de6a687269c4c6e0af61d34: module 14/14 and Claude-plugin family 234/234 passed.
  • Concurrent test-only RED 1684a4c1b5518fd85e8520f8558fe631864035ad: exact-prefix precision produced 2 failed / 1 passed.
  • Exact GREEN head 975e6c38ca8fe4be914845a2e00c291a033998e3, tree 856db31cd9bbcd17e4ca3358f57ca4097de7e748: precision 3/3 and complete tests/test_claude_plugin*.py family 237/237 passed; py_compile and diff check passed.

The current branch is nine ahead / zero behind #1158 and preserves its six-file unique detector/test/docs/workflow delta plus every #1157/#1158 change. Local results are exact-tree evidence, not repository-wide suite, coverage, hosted, approval, or release evidence.

Landing gate

Keep Draft. This custom-base PR currently has no hosted workflow runs or independent review. Before Ready/merge: obtain exact-head detector coverage, applicable Security/SAST/CodeQL, and qualifying independent review. Do not transfer predecessor coverage or results.

No force push, destructive rebase, self-approval, scanner suppression, source-neutral retrigger, stale evidence transfer, or protection bypass.

Relates to #1099. Relates to #1158. Relates to #1137.

RED contract for named secrets in MCP server env, args, and command
strings. Network and prompt copies stay their own classes. Relates to
#1099.
Fail closed when MCP env, args, or command carry a named secret.
Network and prompt copies stay their own classes. Relates to #1099.
@coderabbitai

coderabbitai Bot commented Sep 7, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

seonghobae added a commit that referenced this pull request Sep 7, 2026
Summary:
- Snapshot 19:03 UTC records Draft #1161 `a92e936` stacked on #1158.
- Named secrets in MCP env/args/command fail closed.
- Jules #1159 empty-host SSRF stays Draft under #1068.

Rationale:
- #999 is the single writer of the product-technical gap baseline.
- #1099 remaining surfaces stay on stacked successors, not Close.

Tests:
- documentation-only; detector evidence lives on #1161 (1929/1929)
seonghobae added a commit that referenced this pull request Sep 7, 2026
Summary:
- Snapshot 19:15 UTC records Draft #1163 `cd5560e` stacked on #1161.
- commands/*.md and named agents/*.md reuse released injection/exfil identities.
- README and root AGENTS.md stay repository guidance.

Rationale:
- #999 is the single writer of the product-technical gap baseline.
- #1099 remaining surfaces stay on stacked successors, not Close.

Tests:
- documentation-only; detector evidence lives on #1163 (1934/1934)

Copy link
Copy Markdown
Contributor Author

Successor Draft #1163 (cd5560e) stacks unique command/named-agent markdown #1036 reuse on this head. Keep #1161 Draft. Do not Close.

@seonghobae seonghobae added enhancement New feature or request priority: critical Immediate blocker, P0, urgent deadlock, or critical incident labels Sep 8, 2026 — with ChatGPT Codex Connector

Copy link
Copy Markdown
Contributor Author

Current-head repair finding at 1684a4c1b5518fd85e8520f8558fe631864035ad: _SECRET_REF accepts a named-secret prefix because the shell-variable branch has no identifier boundary. Consequently $OPENAI_API_KEY_DOCUMENTATION and ${OPENAI_API_KEY_DOCUMENTATION} are classified as references to OPENAI_API_KEY, creating false-positive admission failures. I encoded this as a test-only semantic RED in tests/test_claude_plugin_secret_to_mcp_reference_precision.py; the same fixture keeps ${OPENAI_API_KEY:-} fail-closed so the fix cannot simply reject shell parameter expansion.

Exact GREEN acceptance: match only an exact named environment variable token (including normal $NAME, ${NAME}, and shell operators on the exact braced name where supported), never a longer identifier sharing the prefix; preserve #1158 prompt/log semantics, #1137 network classification, secret/bidi-free snippets, and the existing receipt/SARIF contracts. The current PR base is another feature branch, while product Tests is configured for PRs targeting develop/main, so absence of a hosted run on this test-only head is not GREEN evidence. Keep Draft until the causal production fix is present and the eventual canonical/restacked exact head executes the product/security gates.

Copy link
Copy Markdown
Contributor Author

Current-head RED→GREEN evidence for 975e6c38ca8fe4be914845a2e00c291a033998e3 (tree 856db31cd9bbcd17e4ca3358f57ca4097de7e748):

  1. Ordinary two-parent restack ab73726c... preserves prior feat(scanner): reject plugin secrets copied into MCP env and args #1161 and current feat(scanner): reject plugin secret-to-prompt and secret-to-log flows #1158; no force update.
  2. FP RED 172c260d...: 3 failed / 9 deselected. Root cause was unbounded substring matching of secret names in inert MCP args/command prose and longer env keys.
  3. FP GREEN 9303bfe4...: exact env-key matching plus actual-reference parsing; module 12/12 and Claude-plugin family 232/232.
  4. Supported-surface RED 89cc8c33...: URL/header secret references 2 failed / 12 deselected. Claude Code documents expansion in command, args, env, url, and headers: https://code.claude.com/docs/en/mcp
  5. Surface GREEN 9d4c2cf0...: module 14/14 and family 234/234.
  6. Concurrent exact-prefix RED 1684a4c1...: 2 failed / 1 passed for longer variable prefixes while exact ${OPENAI_API_KEY:-} stayed positive.
  7. Final one-file GREEN 975e6c38...: precision 3/3, complete tests/test_claude_plugin*.py family 237/237, compile and diff checks clean.

The PR is nine ahead / zero behind #1158 and mergeable. It remains Draft because this custom-base head has no hosted workflows or qualifying independent review. These local exact-tree results do not transfer predecessor coverage, authorize merge, or close #1099.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request priority: critical Immediate blocker, P0, urgent deadlock, or critical incident

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant