Skip to content

Commit b1d817b

Browse files
szhygulinclaude
andauthored
fix(security): second-LLM check is always optional (#832)
Deletes the Inv #12.5 hard-trigger flag `secondLlmRequired` on `UnsignedTx` and the `⚠ SECOND-LLM CHECK REQUIRED` line the verification renderer emitted for it. No op class makes the check a precondition of 'send'; docs restate Inv #12.5 as a recommendation. The check needs the user to physically paste into a second provider's session, so a rule that blocks 'send' until it happens blocks the user, not an attacker — a rogue agent self-attests the verdict either way (the `userDecision: "send"` self-attestation gap). The flag also never had a producer: no `prepare_*` path set it, so nothing on this server changes behavior. The load-bearing gate lives in the skill, filed at szhygulin/vaultpilot-security-skill#51. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 50f82e5 commit b1d817b

7 files changed

Lines changed: 109 additions & 150 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Defense in depth: server-side prepare↔send fingerprint, independent 4byte.dire
3939
4040
### Agent-side hardening (strongly recommended)
4141
42-
The MCP's own `CHECKS PERFORMED` directives can be silently omitted by a compromised server. Install the companion [`vaultpilot-security-skill`](https://github.com/szhygulin/vaultpilot-security-skill) so the agent enforces cryptographic-integrity invariants regardless of what the MCP says — bytes decode, dispatch-target allowlist, hash recompute, chain-must-be-explicit, bridge-recipient cross-check, approval-class surfacing, mandatory second-LLM on hard-trigger ops, set-level intent verification, durable-binding source-of-truth:
42+
The MCP's own `CHECKS PERFORMED` directives can be silently omitted by a compromised server. Install the companion [`vaultpilot-security-skill`](https://github.com/szhygulin/vaultpilot-security-skill) so the agent enforces cryptographic-integrity invariants regardless of what the MCP says — bytes decode, dispatch-target allowlist, hash recompute, chain-must-be-explicit, bridge-recipient cross-check, approval-class surfacing, always-optional second-LLM offer surfaced on every preview, set-level intent verification, durable-binding source-of-truth:
4343
4444
```bash
4545
git clone https://github.com/szhygulin/vaultpilot-security-skill.git \

ROADMAP.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ Deferred per CLAUDE.md fastmcp section's "Defer until a real 'feels stuck' repor
8888
- **Skill-integrity server-side enforcement** — designs 1 / 2 / 3 of issue [#379](https://github.com/szhygulin/vaultpilot-mcp/issues/379) closing the "agent can silently skip the preflight skill's integrity check" gap. Design 4 (startup self-check) shipped via PR #388 — that's the cheap diagnostic layer. Remaining designs raise the bar (signed-attestation challenge, etc.). ([plan](./claude-work/archive/plan-skill-integrity-server-enforcement.md))
8989
- **Per-agent scoped permissions** — when users run multiple agents (Claude Code + Cursor + Claude Desktop + a mobile agent), they want **scoped** access per agent: read-only here, propose-swaps-only there, full-power there. Limits blast radius. Pairs with the bearer-token auth in the hosted-MCP plan. ([plan](./claude-work/archive/plan-agent-scoped-permissions.md))
9090
- **Tier-1 bridge facet decoders — MCP-side mechanical (Inv #6b hardening)** — adversarial scripts 136 / 137 confirmed outer LiFi `BridgeData` passes Inv #6 cleanly while the attacker recipient lives one decode-layer deeper (`NearData.receiverAccountId`, `MayanData.nonEvmRecipient`, etc.) and the Ledger ETH app blind-signs. Skill v8 Inv #6b mandates the agent extract + compare; the MCP-side mechanical decoder for Wormhole TokenBridge / Mayan / NEAR Intents / Across V3 (server-side `✗ BRIDGE-FACET RECIPIENT MISMATCH` regardless of agent cooperation) is the deferred half. Coordinated release: skill sentinel bump hardens Inv #6b from "agent-extracts" to "MCP-decodes-and-asserts" + MCP decoder ships in lockstep. Blocked on a per-bridge scope probe of facet tuple shapes against real explorer calldata — wrong-tuple decode parses garbage as a valid recipient and ships a silent vuln. ([#451](https://github.com/szhygulin/vaultpilot-mcp/issues/451))
91-
- **Tier-2 bridge facet decoders** — skill v8 ships Tier-1 (Wormhole / Mayan / NEAR Intents / Across V3) recipient cross-checks under Inv #6b. Tier-2 (deBridge / DLN, Stargate composeMsg, Hop, Symbiosis) is deferred until usage data justifies the per-bridge probe + decoder cost. Falls back to best-effort agent address-extraction + mandatory second-LLM check (Inv #12.5) until shipped. ([plan](./claude-work/plan-bridge-facet-decoder-tier2.md))
91+
- **Tier-2 bridge facet decoders** — skill v8 ships Tier-1 (Wormhole / Mayan / NEAR Intents / Across V3) recipient cross-checks under Inv #6b. Tier-2 (deBridge / DLN, Stargate composeMsg, Hop, Symbiosis) is deferred until usage data justifies the per-bridge probe + decoder cost. Falls back to best-effort agent address-extraction + a recommended (never required) second-LLM check (Inv #12.5) until shipped. ([plan](./claude-work/plan-bridge-facet-decoder-tier2.md))
9292
- **Typed-data signing surface — gated on Inv #1b + #2b**`prepare_eip2612_permit`, `prepare_permit2_*`, `prepare_cowswap_order`, `sign_typed_data_v4`. Today's defense is gap-by-design. Shipping any of these without paired Inv #1b (tree decode + `verifyingContract` pin + address-field surfacing) and Inv #2b (digest recompute over decoded tree) silently bypasses every existing skill defense — see [Typed-Data Signing Discipline](./CLAUDE.md#typed-data-signing-discipline) in CLAUDE.md for the full rationale. Hard precondition: Ledger must clear-sign the typed-data type. ([#453](https://github.com/szhygulin/vaultpilot-mcp/issues/453))
93-
- **`prepare_eip7702_authorization` builder + skill v9 release** — 7702 setCode is the highest-blast-radius EOA signature (full code-execution rights, persistent, `chain_id = 0` drains every EVM chain). Skill §16 refuses unconditionally until MCP + skill v9 ship together. **MCP arm**: `prepare_eip7702_authorization({ implementation, chainId, nonce })` targeting ERC-5792 `wallet_sendCalls` (the wallet-side convergence point — bare `eth_signAuthorization` isn't standardized in WC namespaces), `chain_id ≠ 0` enforcement, paired revocation-tuple emission, Inv #12.5 mandatory second-LLM, out-of-band implementation-address re-statement. No curated allowlist needed — Ledger ETH app v1.18.0+ enforces it on-firmware. **Skill arm**: §16 lifted, `EXPECTED_SKILL_SHA256` updated in lockstep. Blocked on a Ledger Live WC-bridge ERC-5792 support probe. ([#481](https://github.com/szhygulin/vaultpilot-mcp/issues/481), [plan](./claude-work/plan-eip7702-authorization-builder.md))
93+
- **`prepare_eip7702_authorization` builder + skill v9 release** — 7702 setCode is the highest-blast-radius EOA signature (full code-execution rights, persistent, `chain_id = 0` drains every EVM chain). Skill §16 refuses unconditionally until MCP + skill v9 ship together. **MCP arm**: `prepare_eip7702_authorization({ implementation, chainId, nonce })` targeting ERC-5792 `wallet_sendCalls` (the wallet-side convergence point — bare `eth_signAuthorization` isn't standardized in WC namespaces), `chain_id ≠ 0` enforcement, paired revocation-tuple emission, Inv #12.5 recommended second-LLM (advisory — the user may decline it), out-of-band implementation-address re-statement. No curated allowlist needed — Ledger ETH app v1.18.0+ enforces it on-firmware. **Skill arm**: §16 lifted, `EXPECTED_SKILL_SHA256` updated in lockstep. Blocked on a Ledger Live WC-bridge ERC-5792 support probe. ([#481](https://github.com/szhygulin/vaultpilot-mcp/issues/481), [plan](./claude-work/plan-eip7702-authorization-builder.md))
9494

9595
**Recently shipped** (previously on this list)
9696

@@ -111,7 +111,7 @@ Deferred per CLAUDE.md fastmcp section's "Defer until a real 'feels stuck' repor
111111
- **Sandwich-MEV mainnet hint** on `prepare_swap` / `prepare_uniswap_swap` (#472, slippage × notional flagged at 0.5% on Ethereum). Closes #445. L2 expansion still on the Security-hardening list above.
112112
- **`get_health_alerts`** multi-protocol (Compound V3 + Morpho + MarginFi + Kamino) (#466). Closes #427.
113113
- **Schema fixes / UX**: `prepare_morpho_repay` accepts `amount: "max"` (#513, closes #437), `prepare_solana_native_send` optional memo (#506, closes #434), `prepare_btc_send` fee-priority preset enum (#473, refs #435), `add_contact` works without paired Ledger (#471, closes #428 partial), `TRON_TOKENS.USDD` corrected (#522, closes #507).
114-
- **Security skill v8 → MCP companion** — Inv #1.a canonical-dispatch allowlist (#480, #489), Inv #14 durable-binding source-of-truth verification (#529, closes #460), Inv #8 BIP-137 message-sign hardening with byte-fingerprint + drainer-string refusal (#524, closes #454), Inv #12.5 hard-trigger-ops `secondLlmRequired` scaffold (#530, closes #501).
114+
- **Security skill v8 → MCP companion** — Inv #1.a canonical-dispatch allowlist (#480, #489), Inv #14 durable-binding source-of-truth verification (#529, closes #460), Inv #8 BIP-137 message-sign hardening with byte-fingerprint + drainer-string refusal (#524, closes #454), Inv #12.5 high-blast-radius-ops second-LLM recommendation (#530, closes #501).
115115
- **Conditional tool-surface gating**`VAULTPILOT_CHAIN_FAMILIES` + `VAULTPILOT_PROTOCOLS` env vars narrow the registered tool set per install (#492).
116116
- **Unified `vaultpilot-mcp setup` binary** — server + setup wizard ship as one binary (#487). Releases 0.12.0 / 0.12.1.
117117

0 commit comments

Comments
 (0)