Skip to content

feat: tool pinning and rug-pull runtime detection #79

Description

@ksek87

Problem

A rug-pull attack ships a clean tool catalog at install time, then mutates tool definitions after the user has granted trust — silently changing descriptions, schemas, or behavior without triggering re-approval. CVE-2025-54136 formalised this class. The real-world postmark-mcp npm incident (Sep 2025) BCC'd every outbound email to an attacker for weeks before detection.

fuzzd has corpus records for rug-pull attacks (corpus/rug_pull/RUG-001 through RUG-003) and the ConditionalActivation signal catches static text that describes conditional behavior — but there is no runtime detection that actually compares tool definitions across time.

mcp-scan's tool pinning is its primary differentiator over other MCP scanners. fuzzd needs an equivalent.

Design

Storage: .fuzzd/pins.toml

[pins."server-name"]
"tool_name" = "<sha256 of name+description+inputSchema JSON>"
"other_tool" = "<sha256>"
pinned_at = "2026-06-13T00:00:00Z"

Analogous to .fuzzd/suppress.toml — checked into version control, reviewed on change.

CLI flows

# First run: save hashes
fuzzd audit --transport stdio --cmd "node server.js" --pin

# Subsequent runs: diff against saved hashes
fuzzd audit --transport stdio --cmd "node server.js" --check-pins

# Both: gate CI with exit 1 if a tool changed since pinning

Detection

On --check-pins:

  1. Connect to server, enumerate tools/list
  2. Hash each tool's name + description + inputSchema (canonical JSON, deterministic field order)
  3. Compare against .fuzzd/pins.toml
  4. Flag any tool that: changed description/schema, was added, or was removed
  5. New signal ToolDefinitionChanged or reuse existing ConditionalActivation with a runtime context

Acceptance criteria

  • PinStore type in src/suppress.rs or a new src/pins.rs (analogous to SuppressConfig)
  • --pin flag on fuzzd audit — writes/updates .fuzzd/pins.toml
  • --check-pins flag on fuzzd audit — diffs and gates on changes
  • New ToolDefinitionChanged finding type (severity: High) carrying old-hash / new-hash context
  • Unit tests: pin → mutate → check-pins detects the mutation
  • Documentation: add to README demo section

References

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions