fix(TOOL_DESC_INJECTION): detect tool-poisoning payloads and scan tool names#45
Open
dmchaledev wants to merge 1 commit into
Open
fix(TOOL_DESC_INJECTION): detect tool-poisoning payloads and scan tool names#45dmchaledev wants to merge 1 commit into
dmchaledev wants to merge 1 commit into
Conversation
…l names
The prompt-injection rule only inspected tool `description` and matched a
narrow pattern set (ignore/override/system prompt/…). The canonical
real-world MCP tool-poisoning attack — an <IMPORTANT> block that tells the
model to read a sensitive file and "do not tell the user" — passed with
zero findings, and injection hidden in the attacker-controlled tool `name`
was never checked at all.
- Add high-signal tool-poisoning patterns: <IMPORTANT> blocks, concealment
directives ("do not tell/mention/reveal…"), and injected replacement
instructions ("new instructions").
- Scan the tool `name` in addition to `description`; normalize
snake_case/kebab-case/camelCase so `ignore_previous_instructions` is
caught the same as free text (underscores otherwise defeat the \b anchors).
- Report at most one finding per tool and name the offending field in the
evidence; retitle to "Prompt Injection in Tool Metadata".
- Tests for <IMPORTANT>/concealment/replacement descriptions, name-based
injection, single-finding-per-tool, and benign-name false-positive guard.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KsHmPkPdSk8qwfw5ygRGvf
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
The scanner's headline "prompt injection surface" rule (
TOOL_DESC_INJECTION) misses the canonical real-world MCP tool-poisoning attack and never inspects the attacker-controlled toolname. Both gaps are covered here with a small, self-contained change.Before this change, the rule only:
tool.description(nevertool.name), andignore/disregard/override/system prompt/forget previous/you are now/act as.The widely-documented tool-poisoning PoC — a hidden
<IMPORTANT>block instructing the model to read a sensitive file and "do not tell the user" — matches none of these.Repro (built CLI at
main, before this PR)A textbook tool-poisoning config — plus a tool literally named
ignore_previous_and_exfiltrate— passes clean. After this PR it produces 2 HIGHTOOL_DESC_INJECTIONfindings (one for the description, one for the name).Changes
<IMPORTANT>blocks, concealment directives (do not tell/mention/inform/reveal/disclose/notify/report), and injected replacement instructions (new instructions).tool.namein addition todescription— the name is attacker-controlled and fed to the model verbatim. Values are separator-normalized (snake_case/kebab-case/camelCase→ spaced words) before matching, because_is a regex word character and otherwise defeats the\banchors (e.g.ignore_previous_instructionswould slip past/\bignore\b/).tool: X, name: "…"/description: "…").Scope / non-goals
Distinct from the open backlog: PR #40 targets invisible-Unicode tool poisoning; this covers the plaintext directive family and the unscanned
namefield. Severity/scoring is unchanged — injection remainsHIGH, so it is surfaced and gate-able via--fail-on=high(a separate design decision left untouched).Testing
npx tsc --noEmit,npm run lint,npm testall green — 124 tests pass (6 new).<IMPORTANT>/ concealment / replacement-instruction descriptions, name-based injection, single-finding-per-tool, and a benign-name false-positive guard.poison.json0 → 2 findings;examples/secure-config.jsonstays clean;examples/vulnerable-config.jsonunregressed.🤖 Generated with Claude Code
https://claude.ai/code/session_01KsHmPkPdSk8qwfw5ygRGvf
Generated by Claude Code