Skip to content

fix(decode): independently surface safeTransferFrom recipient + tokenId - #679

Merged
szhygulin merged 2 commits into
mainfrom
fix/670-erc721-decode-calldata
Jun 11, 2026
Merged

fix(decode): independently surface safeTransferFrom recipient + tokenId#679
szhygulin merged 2 commits into
mainfrom
fix/670-erc721-decode-calldata

Conversation

@szhygulin

Copy link
Copy Markdown
Collaborator

Re: #670 (which is closed as architectural — full agent+MCP collusion is undefendable here; this is the cooperating-agent / rogue-MCP-only defense-in-depth slice).

Adds the two ERC-721 safeTransferFrom selectors (0x42842e0e, 0xb88d4fde) to the independent calldata decoder's HIGH_RISK_STANDARD_SELECTORS in src/signing/decode-calldata.ts, mirroring the merged #573 setApprovalForAll fallback. On an uncurated NFT destination reached via prepare_custom_call, the recipient (to) and tokenId (and from) now surface in CHECKS PERFORMED, independently decoded — so a cooperating agent + user see the real recipient even if the MCP-reported summary lies.

  • 4-arg safeTransferFrom(...,bytes) form: added a dynamicTail flag with a minimum-length head guard (the dynamic bytes tail makes total length variable); viem's decodeFunctionData validates the encoding and the data payload is surfaced so a hook-bearing transfer can't hide it.
  • test/nft-operator-approval-decode.test.ts (+12): genuine fail-before (3 positive-decode tests fail without the selectors) / pass-after.

Scope: this does NOT defend the full agent+MCP collusion in #670 (an independent decode that runs inside a rogue MCP is adversary-controlled; the residual anchor is on-device clear-sign, tracked at #453). It hardens the rogue-MCP-only case. The skill-side ERC-721 / collection-offer decoder companion (Inv #17) is being filed in szhygulin/vaultpilot-security-skill (linked in a comment below).

🤖 Generated with Claude Code

Adds ERC-721 safeTransferFrom selectors (0x42842e0e, 0xb88d4fde) to the
independent calldata decoder's HIGH_RISK_STANDARD_SELECTORS, mirroring the
#573 setApprovalForAll fallback, so the NFT recipient and tokenId surface in
CHECKS PERFORMED on uncurated destinations (rogue-MCP-only / cooperating-agent
defense-in-depth). Re: #670.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@szhygulin

Copy link
Copy Markdown
Collaborator Author

Cross-repo companion filed: szhygulin/vaultpilot-security-skill#50 — Inv #17, the skill-side ERC-721 / collection-offer decoder that surfaces the proceeds recipient distinct from the asset recipient. Scope: cooperating-agent guidance only; a rogue agent ignores it.

…ality

Review follow-up: the HighRiskSelector doc comment claimed a module-load
`assertSelectorMatches` guard that does not exist. Corrected to describe the
actual pinning mechanism — the per-entry decode tests assert each selector
against its calldata, so a mistyped selector fails in CI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@szhygulin
szhygulin merged commit e461d7c into main Jun 11, 2026
3 checks passed
@szhygulin
szhygulin deleted the fix/670-erc721-decode-calldata branch June 11, 2026 01:31
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 11, 2026
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.

1 participant