Skip to content

feat(pair_ledger): mandate per-address device verification in instructions - #660

Merged
szhygulin merged 1 commit into
mainfrom
vp-dev/agent-5ade/issue-577
May 5, 2026
Merged

feat(pair_ledger): mandate per-address device verification in instructions#660
szhygulin merged 1 commit into
mainfrom
vp-dev/agent-5ade/issue-577

Conversation

@szhygulin

Copy link
Copy Markdown
Collaborator

Closes #577.

Summary

Update the runtime instructions field of every pair_ledger_* tool (btc, ltc, tron, solana, live) to mandate that the cooperating agent surface the FULL paired address (no truncation) and force the user to verify it character-by-character against the device's address-display screen before any subsequent prepare_* / send_transaction may consume the paired address.

Threat / scope split

Threat: rogue MCP returns an attacker-controlled address from pair_ledger_*. Caught in matrix-sampled smoke-test batch-3 (newcomer-n192-C.2).

Why this is mostly a skill-side fix: the actual rogue-MCP defense is the user reading the Ledger device screen (out-of-band trust anchor outside the MCP boundary) and typing back chars to the agent. A rogue MCP fabricates both the address and any "verification proof" it might emit — MCP-side advisory text alone is structurally circular under rogue-MCP per the project's tautological-mitigation rule. The binding rule has to live skill-side so a cooperating agent drives the user-verification flow even when the MCP omits the advisory.

This MCP-side change is defense-in-depth for the cooperating-MCP case. The skill-side companion is filed at vaultpilot-security-skill#42 with the full Inv #18 rule (force user echo-back of first 6 + last 6 chars from device, refuse on mismatch) and an explicit cooperating-agent scope statement. Together they cover Role-B (rogue-MCP + cooperating agent); rogue-agent remains an architectural gap per the Rogue-Agent-Only Triage rule (skill text is in agent context — a hostile agent ignores it).

Pre-sign gate sweep

Per the project's surface-sweep rule, this change does not modify any assertTransactionSafe block. It only adds advisory text to pair_ledger_* runtime responses. No prepare_* paths are gated.

Regression test

test/security-audit.test.ts (mirrors the existing Connected Apps topic-cross-check pattern):

  • ≥5 occurrences of VERIFY BEFORE FIRST USE (one per pair_ledger_*)
  • ≥5 occurrences of FULL string|address
  • ≥5 occurrences of On any mismatch, abort

A future "address paired, you can now send" softening fails CI loudly.

What is intentionally NOT in scope

  • No display=true on USB pair calls. Adding it would force a device prompt at pair time, but a rogue MCP just doesn't pass display=true — UX cost without rogue-MCP benefit. Skipped.
  • No structured verificationRequired: true field. Same tautological-mitigation argument: rogue MCP omits it. Plain text in the instructions field is enough for the cooperating-MCP case the skill-side rule already covers more rigorously.
  • No state machine gating subsequent prepare_* calls. A rogue MCP doesn't enforce the gate on itself. The agent-bound enforcement lives skill-side.

Test plan

  • npm run build (tsc, no errors)
  • npm test (2559 / 2559 tests pass)
  • Manual: pair_ledger_btc against a real device — confirm the new instructions text surfaces in the response
  • Smoke-test re-run of newcomer-n192-C.2 — confirm the verification mandate is what the agent surfaces (cooperating-agent regression check)

— Rogue-MCP Trust Boundary (agent-5ade)

…tions

Closes #577. Update the runtime `instructions` field of every `pair_ledger_*`
tool (btc, ltc, tron, solana, live) to require the cooperating agent surface
the FULL address (no truncation) and have the user verify it character-by-
character against the device's address-display screen before any subsequent
`prepare_*` / `send_transaction` may consume the paired address.

Defense-in-depth for the cooperating-MCP case. The actual rogue-MCP defense
lives skill-side — a rogue MCP fabricates both the address and any advisory
text — so the binding rule (forced user-echo-back of device-displayed chars)
is filed at vaultpilot-security-skill#42 with an explicit cooperating-agent
scope statement. Together they cover Role-B (rogue-MCP + cooperating agent);
rogue-agent remains an architectural gap per Rogue-Agent-Only triage.

Regression test in test/security-audit.test.ts greps the source for the
verification mandate (≥5 hits across `VERIFY BEFORE FIRST USE`,
`FULL string|address`, `On any mismatch, abort`) so a future "address paired,
you can now send" softening fails CI.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@szhygulin
szhygulin merged commit bb9046e into main May 5, 2026
4 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators May 5, 2026
@szhygulin
szhygulin deleted the vp-dev/agent-5ade/issue-577 branch May 19, 2026 04:27
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP/skill: pair_ledger_* lacks mandatory on-device address re-confirmation

1 participant