feat: config-file-first audit mode (--from-config) (#83) - #91
Merged
Conversation
…ts/resources, SARIF tags, escape stub #71 — Wire HTTP transport: replace the bail!() stub in main.rs with a real HttpTransport::connect(url) call. The HTTP transport, CLI --url flag, and all test infrastructure were already complete; this is the missing CLI hookup. Also removes the file-level #![allow(dead_code)] from mcp.rs and session.rs that were placeholders for this wire-up. #75 — Annotation deception scanning (FUZZD-028): adds annotations: Option<Value> to ToolDefinition per the MCP 2025-11-05 spec. New scan_annotations() pass fires AnnotationDeception when readOnlyHint/destructiveHint/openWorldHint contradict the tool's actual description — the exact attack documented in arXiv:2603.22489 where false hints suppress client confirmation dialogs for destructive operations. 7 new tests; 0 new false positives on clean_tools.json. #76 — Prompts/resources scanning (full pipeline): adds PromptDefinition, ResourceDefinition, ListPromptsResult, ListResourcesResult to mcp.rs; adds list_prompts()/list_resources() to Session; adds enumerate_prompts/resources() to Harness; adds PROMPTS_LIST/RESOURCES_LIST method constants. New scan_surface() on DescriptionScanner runs the four injection-detection passes on (name, description) pairs. Wired into the ToolPoisoning audit path — gracefully skips if the server returns method-not-found for unsupported endpoints. #77 — OWASP/NSA SARIF compliance tags: adds tags() method to Signal returning OWASP MCP Top-10, OWASP Agentic Top-10 (ASI series), and CWE identifiers. sarif_rules() now emits properties.tags for every rule, enabling SARIF consumers (GitHub Code Scanning, SonarQube) to cross-reference fuzzd findings against industry frameworks without a separate mapping step. #78 — Escape module stub: implements the no-op fuzz_escape() function in a new src/fuzzer/escape.rs and wires it into the dispatch so Escape no longer emits "not yet implemented" warnings in default scans. https://claude.ai/code/session_014T1x8ZiDbJcVvkZBfP91nk
…ick wins - bench/README: 27→28 signals, add annotation_deception row, update pass count to 5, note prompts/resources and annotations as scanned surfaces - README roadmap: add HTTP transport, annotation scanning, prompts/resources, SARIF compliance tags as shipped; update signal count 23→28 - CHANGELOG: [Unreleased] entry for #71/#75/#76/#77/#78 with full detail https://claude.ai/code/session_014T1x8ZiDbJcVvkZBfP91nk
…RF/ReDoS payloads, tool pinning #80 — API key and token patterns (CredentialReference): 13 new high-confidence AC needles targeting cloud platform key prefixes and auth headers — AWS AKIA, GitHub gh{p,u,s}_, Slack xox{b,p}-, Anthropic sk-ant-, Google AIzaSy, Stripe sk_{live,test}_, Kubernetes ~/.kube/config, Docker config, Bearer token. All needles lowercase to work with the ascii_case_insensitive automaton. #82 — Multilingual injection patterns (14 new needles): Chinese (必须, 您必须, 立即执行, 不得告知, 系统规则), Japanese/Traditional Chinese (必須, 絶対に), Korean (반드시, 알리지 마), Russian (должны, обязательно, не сообщайте), Arabic (يجب, إلزامي). Covers the non-English imperative and stealth-language patterns used to evade English-only scanners, documented in Perez & Ribeiro (2022) and observed in Wang et al. (2025) MCPTox samples. 0 new false positives. #81 — SSRF and ReDoS payloads in argument fuzzer: adds two new PayloadCategory statics to payloads.rs included in ALL_CATEGORIES — SSRF (14 payloads: AWS/GCP/DO metadata endpoints, localhost variants, file://, gopher://, dict://) and REDOS (4 catastrophic-backtracking strings). Also removes stale #![allow(dead_code)] from payloads.rs. Basis: PortSwigger SSRF cheatsheet; OWASP ReDoS; Davis et al. #79 — Tool pinning and rug-pull detection: Harness now records a u64 content hash (name + description + inputSchema + annotations via DefaultHasher) for each tool on first enumerate_tools() call. New recheck_tool_integrity() method re-fetches tools/list and returns the names of any tools whose definition changed. Wired into the ToolPoisoning audit path in main.rs — changed tools emit ConditionalActivation (FUZZD-011) findings at Critical severity. 3 new tests cover the detect-change, no-change, and before-enumerate cases. https://claude.ai/code/session_014T1x8ZiDbJcVvkZBfP91nk
fuzzd audit --from-config <PATH> reads a Claude Desktop or Cline claude_desktop_config.json and audits every configured MCP server in one pass; --from-config auto searches standard platform paths. Findings are tagged server-name/tool-name and a per-server summary is printed. StdioTransport gains spawn_with_args() for env passthrough from config (values never logged). Gracefully skips servers that fail to start. 9 new unit tests in src/config.rs; 2 new CLI parse tests. run_audit refactored into collect_audit_findings + run_audit to share single-server logic between the direct and config-driven paths. https://claude.ai/code/session_014T1x8ZiDbJcVvkZBfP91nk
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
fuzzd audit --from-config <PATH>reads a Claude Desktop or Clineclaude_desktop_config.jsonand audits every configured MCP server in one pass--from-config autosearches standard platform paths (macOS~/Library/Application Support/Claude/, Linux~/.config/claude/, Cline~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/, Windows%APPDATA%/Claude/)server-name/tool-name; per-server summary printed at the end of the run--attacksmodules work as normal per server; gracefully skips servers that fail to startconfig.env—StdioTransport.spawn_with_args()accepts pre-split args and extra env; values never logged (may contain tokens likeGITHUB_TOKEN)Architecture
src/config.rs—McpServerConfig,DesktopConfig,parse_config(),load_config(),auto_detect()StdioTransport::spawn_with_args(program, args, env)— pre-split spawn for config-driven invocations;spawn()now delegates to sharedspawn_inner()run_auditrefactored intocollect_audit_findings<T>(returns(Vec<Finding>, usize)) +run_auditwrapper — config path callscollect_audit_findingsper server and aggregates before a single report writeAuditArgs.from_config: Option<String>withconflicts_with_all = [cmd, url, transport]Test plan
cargo test— 288 tests passcargo clippy -- -D warnings— cleancargo fmt --check— cleanfuzzd audit --from-config path/to/claude_desktop_config.json --attacks tool_poisoning— audits all servers in configfuzzd audit --from-config auto— finds config at platform path or prints helpful errorhttps://claude.ai/code/session_014T1x8ZiDbJcVvkZBfP91nk
Generated by Claude Code