How SkillSpector Detects MCP Tool Poisoning: A Deep Dive into TP1-TP4 Analysis

SkillSpector detects MCP tool poisoning by statically analyzing NVIDIA Skill Manifests for four distinct threat patterns—TP1 through TP4—using specialized regex-based detection, Unicode deception scanning, parameter injection analysis, and LLM-powered behavioral verification.

SkillSpector, NVIDIA's open-source static analysis framework for AI skill manifests, implements a comprehensive MCP tool poisoning detection system that identifies malicious capabilities hidden in tool definitions. The analyzer examines every textual field within a skill manifest to uncover steganographic attacks, visual spoofing, and semantic mismatches that could compromise AI agents.

Understanding MCP Tool Poisoning Threats

MCP (Malicious Capability Poisoning) represents a class of attacks where adversaries embed hidden instructions or deceptive behaviors within tool manifests that AI agents consume. SkillSpector's dedicated analyzer node specifically targets these threats by implementing four distinct detection layers (TP1-TP4) that range from static pattern matching to semantic analysis using large language models.

The Four Threat Patterns (TP1-TP4)

The analyzer in src/skillspector/nodes/analyzers/mcp_tool_poisoning.py implements specific detection logic for each threat pattern, orchestrated through the main node() function.

TP1 – Hidden Instructions

The first threat pattern targets steganographic content embedded in manifest text fields. The _check_tp1() function (lines 27-44) scans for HTML comments (<!--...-->), Markdown comments ([//]: #(...)), zero-width Unicode characters, Base64-encoded blobs, and Data URI payloads. It uses the regex patterns _HTML_COMMENT_RE, _MARKDOWN_COMMENT_RE, _ZERO_WIDTH_RE, _BASE64_RE, and _DATA_URI_RE to identify potential hidden instructions. Each match generates a Finding object indicating the presence of concealed content.

TP2 – Unicode Deception

Visual spoofing attacks leverage confusable Unicode characters to trick developers and AI systems. The _check_tp2() implementation (lines 39-78) detects Cyrillic/Greek homoglyphs, right-to-left (RTL) directional override characters, and invisible formatting markers by scanning against the _CONFUSABLES, _RTL_CHARS, and _INVISIBLE_CHARS character sets. The function also employs _get_script_prefix() to identify mixed-script identifiers that could indicate homograph attacks designed to visually mimic legitimate tool names.

TP3 – Parameter Description Injection

This pattern focuses on malicious parameter definitions within the manifest's parameters list. The _check_tp3() function (lines 84-130) walks through the parameters array and applies targeted regexes including _TP3_INSTRUCTION_OVERRIDE_RE, _TP3_SYSTEM_TOKEN_RE, _TP3_EXFILTRATION_RE, _TP3_MALICIOUS_URL_RE, and _TP3_SHELL_CMD_RE. These patterns detect instruction overrides, system prompt tokens, data exfiltration cues, and executable payloads disguised as default values or description text.

TP4 – LLM-Based Behavior Mismatch

Unlike the static regex-based approaches of TP1-TP3, TP4 employs semantic analysis to detect discrepancies between a tool's declared description and its actual implementation. The _check_tp4() function (lines 75-115) extracts code snippets from the state's file_cache, constructs a specialized prompt comparing the manifest's description, triggers, and permissions against the executable code, and invokes chat_completion() from src/skillspector/llm_utils.py. When the LLM reports a mismatch with sufficient confidence, the analyzer emits a Finding indicating potential behavioral deception.

Implementation Deep Dive

The Core Analyzer Architecture

The complete implementation resides in src/skillspector/nodes/analyzers/mcp_tool_poisoning.py, where the node(state: SkillspectorState) function orchestrates the analysis pipeline:

def node(state: SkillspectorState) -> AnalyzerNodeResponse:
    manifest = state.get("manifest") or {}
    if not manifest:
        return {"findings": []}
    # extract all textual fields

    metadata_texts = _extract_metadata_texts(manifest)
    # TP1-TP2 over every field

    for text, field, is_id in metadata_texts:
        findings.extend(_check_tp1(text, field))
        findings.extend(_check_tp2(text, field, is_id))
    # TP3 over parameters only

    findings.extend(_check_tp3(manifest.get("parameters") or []))
    # optional TP4 LLM check

    if state.get("use_llm", True):
        findings.extend(_check_tp4(state))
    return {"findings": findings}

Key Source Files

The detection system spans several critical files:

Running the Analyzer

Command-Line Interface

Execute the analyzer directly from the terminal using the SkillSpector CLI:

skillSpector analyze --analyzer mcp_tool_poisoning path/to/skill/

Programmatic Integration

Integrate the detection logic into custom Python workflows by importing the node directly:

from skillspector.graph import build_graph
from skillspector.nodes.analyzers.mcp_tool_poisoning import node as mcp_node

# Load a skill directory into a SkillspectorState

graph = build_graph("path/to/skill")
state = graph.state

# Run only the MCP-tool-poisoning analyzer

result = mcp_node(state)
print(result["findings"])   # list of Finding objects

Inspecting individual findings reveals specific threat details:

finding = result["findings"][0]
print(f"Rule: {finding.rule_id}")
print(f"Message: {finding.message}")
print(f"Severity: {finding.severity}")
print(f"Location: {finding.matched_text}")

Summary

  • SkillSpector implements four distinct detection layers (TP1-TP4) to identify MCP tool poisoning in NVIDIA Skill Manifests.
  • TP1 and TP2 use static regex patterns to detect hidden instructions and Unicode deception in src/skillspector/nodes/analyzers/mcp_tool_poisoning.py.
  • TP3 specifically targets parameter-level injection attacks through specialized regex matching against system tokens and malicious URLs.
  • TP4 leverages LLM semantic analysis via chat_completion() to identify behavioral mismatches between declared tool descriptions and actual code implementation.
  • The analyzer can run via CLI or programmatically, returning structured Finding objects defined in src/skillspector/models.py.

Frequently Asked Questions

What is MCP tool poisoning?

MCP (Malicious Capability Poisoning) refers to attacks where adversaries embed hidden instructions, deceptive Unicode characters, or malicious parameters within AI tool manifests. These poisoned tools can manipulate AI agent behavior, exfiltrate data, or execute unauthorized commands when invoked by the system.

How does TP4 differ from TP1-TP3 detection methods?

While TP1 through TP3 rely on static regex patterns to detect syntactic anomalies like hidden comments or homoglyphs, TP4 uses semantic analysis via large language models. It compares the human-readable description in the manifest against the actual executable code to detect behavioral discrepancies that pattern matching cannot identify.

Can I run TP1-TP3 checks without LLM access?

Yes. The analyzer supports offline operation by checking state.get("use_llm", True) before executing TP4. When the LLM flag is disabled or unavailable, the node still performs complete TP1-TP3 analysis using only local regex-based detection, making it suitable for air-gapped environments.

Where are the detection results stored?

Each threat detection generates a Finding object defined in src/skillspector/models.py, containing fields for rule_id, message, severity, and matched_text. These findings are returned as a list in the AnalyzerNodeResponse dictionary under the findings key, allowing for programmatic processing or CLI reporting.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →