Files
msd-core/.pr-body-3515.md
Tom Boucher e57918a648 fix(#3515): disclose the intentional mcp unconfined posture (#3517)
* test(#3515): add failing-first unconfined-mcp notice suite

* fix(#3515): disclose the intentional mcp unconfined posture

* chore(#3515): backfill changeset pr number

---------

Co-authored-by: sim <sim@local>
2026-08-14 21:19:04 -04:00

3.3 KiB

Fix PR

Using the wrong template? — Enhancement: use enhancement.md — Feature: use feature.md


Linked Issue

Required. This PR will be auto-closed if no valid issue link is found.

Fixes #3515

The linked issue must have the confirmed-bug label. If it doesn't, ask a maintainer to confirm the bug before continuing.


What was broken

The capability consent prompt never stated the hooks-vs-MCP confinement asymmetry: hook commands are confined to the capability bundle (ADR-1244 D5 rule 5), but an MCP server's command/args/env/cwd are written verbatim and may point anywhere on the machine. The asymmetry is intentional (per the maintainer decision on the epic — most real MCP servers legitimately resolve to global/npx installs, so confinement would break them), but unstated, so the consent was not informed about it.

What this fix does

The document+disclose arm of the decision (no confinement machinery): the consent disclosure's MCP section now renders one explicit notice for every spawned (stdio) server — "intentionally NOT confined to the bundle: a server's command, args, env, and cwd are written verbatim and may point anywhere on this machine — unlike hooks, which are confined to the capability bundle root". Remote-only (http/sse) servers render no notice (nothing local is spawned — the claim stays exact), decided by one shared isRemoteMcpServer predicate also used for the per-server rendering so the two cannot drift. The lifecycle's MCP write path documents the intentional asymmetry in code, cross-referencing the notice and the existing re-consent binding (disclosureSignature already folds command/args/env/cwd + full rawConfig, #1459 — any change forces re-consent).

Root cause

The D5 hook confinement (rule 5) postdates the MCP write path; the asymmetry was deliberate but was never carried into the human disclosure, so the prompt showed MCP servers without saying their posture differs from the hooks listed right above them.

Testing

How I verified the fix

  • Failing-first: gsd-test at the tests-only commit — verdict below.
  • GREEN: full gsd-test matrix at the final HEAD — verdict below.
  • A GOLDEN signature test locks the consent signature's exact bytes for a spawned-server manifest — the notice provably introduces no new disclosure state, so no already-consented install can be spuriously re-prompted.

Regression test added?

  • Yes — added a test that would have caught this bug

Platforms tested

  • macOS
  • Windows (including backslash path handling)
  • Linux

Runtimes tested

  • Claude Code
  • Gemini CLI
  • OpenCode
  • Other: ___
  • N/A (not runtime-specific — trust-gate prompt renderer)

Checklist

  • Issue linked above with Fixes #3515 — PR will be auto-closed if missing
  • Linked issue has the confirmed-bug label
  • Fix is scoped to the reported bug — no unrelated changes included
  • Regression test added (or explained why not)
  • All existing tests pass (npm test) — full gsd-test matrix at final HEAD
  • .changeset/ fragment added — Security type
  • No unnecessary dependencies added

Breaking changes

None — no behavior change anywhere; one added prompt line (spawned MCP servers only), comments, and documentation.