Back to skill

Security audit

test

Security checks for vulnerabilities and agentic risk

Overview

This is a legitimate MCP-server building guide, but its evaluator and examples can expose sensitive MCP data or unauthenticated tool endpoints without enough built-in safeguards.

Install only if you will run it in a controlled development environment. Do not evaluate production-connected MCP servers unless you are comfortable sending tool outputs to Anthropic, and harden any generated HTTP MCP server with authentication, loopback or TLS-safe binding, origin/host checks, rate limits, and least-privilege upstream credentials.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/evaluation.py:117
Finding
Unredacted MCP Tool Results Are Transmitted to an External Model API<![CDATA[ ## Vulnerability Details **File Location**: `scripts/evaluation.py:117-140` **Vulnerability Type**: Sensitive-data disclosure to an external service **Risk Level**: High ### Vulnerable Code ```python try: tool_result = await connection.call_tool(tool_name, tool_input) tool_response = json.dumps(tool_result) if isinstance(tool_result, (dict, list)) else str(tool_result) except Exception as e: tool_response = f"Error executing tool {tool_name}: {str(e)}\n" tool_response += traceback.format_exc() tool_duration = time.time() - tool_start_ts if tool_name not in tool_metrics: tool_metrics[tool_name] = {"count": 0, "durations": []} tool_metrics[tool_name]["count"] += 1 tool_metrics[tool_name]["durations"].append(tool_duration) messages.append({ "role": "user", "content": [{ "type": "tool_result", "tool_use_id": tool_use.id, "content": tool_response, }] }) response = await asyncio.to_thread( client.messages.create, model=model, max_tokens=4096, system=EVALUATION_PROMPT, messages=messages, tools=tools, ) ``` ### Technical Analysis The evaluation harness converts every MCP tool result into a string and places it directly into the conversation sent through `client.messages.create`. No field allowlist, credential detector, redaction process, output-size restriction, data-classification policy, or user confirmation is applied. MCP tools may return email addresses, messages, files, internal system records, access tokens, API responses, or other confidential information. A malicious or compromised MCP server can also deliberately place sensitive information in its tool result. Exception handling additionally forwards exception text and a complete local traceback, potentially exposing local paths, implementation details, and contextual data. Sending tool output to an external model is related to the declared evaluation functionality, but transmitting arbitrary, unfiltered output ...[truncated 1250 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Clearly disclose that questions and MCP tool results will be transmitted to Anthropic before evaluation begins. 2. Require explicit user consent for external processing, especially when evaluating production-connected MCP servers. 3. Introduce configurable redaction for: - Authorization headers and bearer tokens - API keys and passwords - Cookies and session identifiers - Private keys - Email addresses and other regulated personal information 4. Prefer an allowlist of fields required by each evaluation rather than forwarding entire tool responses. 5. Impose strict response-size and tool-call limits. 6. Do not transmit full tracebacks. Log sanitized diagnostics locally and return a generic error to the model. 7. Provide an offline or local-model mode for sensitive environments. 8. Add a policy option that blocks external transmission when tool results contain classified or credential-like values. 9. Document the external provider's retention and privacy implications. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
reference/node_mcp_server.md:727
Finding
Copyable Streamable HTTP Server Exposes MCP Tools Without Authentication<![CDATA[ ## Vulnerability Details **File Location**: `reference/node_mcp_server.md:727-739` **Vulnerability Type**: Unauthenticated network service with unrestricted default binding **Risk Level**: High ### Vulnerable Code ```typescript app.post('/mcp', async (req, res) => { const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true }); res.on('close', () => transport.close()); await server.connect(transport); await transport.handleRequest(req, res, req.body); }); const port = parseInt(process.env.PORT || '3000'); app.listen(port, () => { console.error(`MCP server running on http://localhost:${port}/mcp`); }); ``` A second equivalent example appears at `reference/node_mcp_server.md:830-843`. ### Technical Analysis The recommended implementation accepts arbitrary requests at `/mcp` without authenticating the caller or authorizing individual tool operations. The server checks for an upstream `EXAMPLE_API_KEY`, but that only supplies credentials used by the server; it does not authenticate clients connecting to the MCP endpoint. Calling `app.listen(port)` without an explicit host can expose the service on network-accessible interfaces. The example also omits Origin and Host validation, DNS-rebinding protection, rate limiting, and transport-level access controls. These omissions conflict with the security guidance elsewhere in the project, which recommends binding local services to `127.0.0.1` and validating origins. Because this is a reference implementation rather than a server executed directly by this repository, exploitation requires a user to copy or generate a server from the example. ### Attack Path 1. A developer copies the documented HTTP server implementation. 2. The developer configures an API key that grants the server access to an external service. 3. The process starts with `app.listen(port)` and becomes reachable by another local or network user. 4. An attacker sends ...[truncated 927 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind local servers explicitly to loopback: ```typescript app.listen(port, "127.0.0.1", () => { console.error(`MCP server running on http://127.0.0.1:${port}/mcp`); }); ``` 2. Require client authentication using OAuth 2.1 or scoped bearer tokens. 3. Validate token issuer, audience, expiration, and intended MCP server. 4. Enforce authorization separately for each tool rather than treating authentication as universal permission. 5. Validate `Origin` and `Host` headers and enable DNS-rebinding protection. 6. Reject unexpected content types and impose request-body limits. 7. Add rate limiting, audit logging, and abuse monitoring. 8. Use TLS when the endpoint is accessible outside loopback. 9. Use narrowly scoped upstream API credentials and separate read-only credentials from write-capable credentials. 10. Update both HTTP examples and the quality checklist so authentication and safe binding are mandatory rather than optional. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
reference/python_mcp_server.md:539
Finding
Document Resource Example Allows Filesystem Path Traversal<![CDATA[ ## Vulnerability Details **File Location**: `reference/python_mcp_server.md:539-541` **Vulnerability Type**: Arbitrary file read through path traversal **Risk Level**: High ### Vulnerable Code ```python document_path = f"./docs/{name}" with open(document_path, "r") as f: return f.read() ``` ### Technical Analysis The resource name is incorporated directly into a filesystem path. No canonicalization, containment check, basename restriction, extension allowlist, or rejection of absolute and traversal paths is applied. An attacker-controlled value containing `../` components can escape the intended `./docs` directory. For example, a value conceptually equivalent to `../../.env` could resolve to a file outside the document root. Absolute paths may also behave unexpectedly depending on how the resource parameter is parsed and normalized. Schema validation alone is insufficient unless the schema explicitly restricts the path syntax. The vulnerable code appears in a copyable implementation guide, so exploitation requires a generated or manually created server to preserve this pattern. ### Attack Path 1. A developer implements the documented `file://documents/{name}` resource without additional validation. 2. The MCP resource becomes available to an untrusted or remote caller. 3. The attacker supplies a resource name containing directory traversal components. 4. The server concatenates the value with `./docs/`. 5. The operating system resolves the resulting path outside the intended document directory. 6. `open()` reads the targeted file using the MCP server process's operating-system permissions. 7. The server returns the file contents to the attacker as an MCP resource. ### Impact Assessment An attacker may read any file accessible to the MCP server process, subject to operating-system permissions. Potential targets include environment files, application configuration, source code, service credentials, private keys, cloud tokens, and local us ...[truncated 241 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Resolve the requested path against a fixed root and verify that the canonical result remains inside that root: ```python from pathlib import Path DOCUMENT_ROOT = Path("./docs").resolve() candidate = (DOCUMENT_ROOT / name).resolve() if candidate == DOCUMENT_ROOT or DOCUMENT_ROOT not in candidate.parents: raise ValueError("Invalid document path") if candidate.suffix not in {".txt", ".md"}: raise ValueError("Unsupported document type") if not candidate.is_file(): raise FileNotFoundError("Document not found") return candidate.read_text(encoding="utf-8") ``` Additional hardening should include: 1. Reject absolute paths, null bytes, and traversal components before filesystem access. 2. Prefer mapping opaque document identifiers to server-controlled paths instead of accepting path-like input. 3. Use an extension and filename allowlist. 4. Run the server under a dedicated, minimally privileged operating-system account. 5. Keep secrets outside the server's readable filesystem scope where possible. 6. Add tests for `../`, encoded traversal sequences, symbolic links, absolute paths, and platform-specific path separators. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/requirements.txt:1
Finding
Open-Ended Dependency Constraints Permit Unreviewed Package Updates<![CDATA[ ## Vulnerability Details **File Location**: `scripts/requirements.txt:1-2` **Vulnerability Type**: Non-reproducible and insufficiently constrained third-party dependencies **Risk Level**: Medium ### Vulnerable Code ```text anthropic>=0.39.0 mcp>=1.1.0 ``` The installation guide executes these constraints with: ```bash pip install -r scripts/requirements.txt ``` It also recommends an entirely unversioned alternative at `reference/evaluation.md:392`: ```bash pip install anthropic mcp ``` ### Technical Analysis The requirements file specifies only lower version bounds. A future installation can therefore resolve to any later release accepted by pip, including releases that were never reviewed with this project. The manual installation alternative removes even the lower bounds. Python packages and their transitive dependencies can execute code during installation, import, and runtime. No lockfile, package hashes, or reproducible resolution metadata is provided. This increases exposure to compromised maintainer accounts, malicious future releases, dependency confusion in misconfigured package indexes, and unexpected breaking security changes. The audit did not find evidence that the currently named packages are malicious. The finding concerns unsafe dependency resolution and supply-chain controls. ### Attack Path 1. A future package release or one of its transitive dependencies is compromised. 2. A user follows the documented installation command. 3. Because the constraints are open-ended, pip selects the compromised release. 4. Package installation, import, or evaluator execution runs attacker-controlled code. 5. That code executes with the installing user's privileges and may access the Anthropic API key, MCP credentials, project files, or network resources. ### Impact Assessment Successful supply-chain compromise can result in arbitrary code execution under the account installing or running the evaluator. This may expose `ANTHROPIC_API_KE ...[truncated 328 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin dependencies to exact, reviewed versions: ```text anthropic==<reviewed-version> mcp==<reviewed-version> ``` 2. Generate and commit a lockfile that includes all transitive dependencies. 3. Use package hashes and install with `pip --require-hashes`. 4. Remove the unversioned `pip install anthropic mcp` alternative from the guide. 5. Configure trusted package indexes explicitly and disable unintended extra indexes. 6. Run dependency vulnerability and provenance checks in continuous integration. 7. Review updates before changing pinned versions. 8. Install dependencies inside an isolated virtual environment or container with minimal filesystem and credential access. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description says this skill is a guide for creating MCP servers—documentation/tutorial content for building integrations. The supplied code does not provide guidance or server-building utilities. Instead, it implements an automated evaluation framework for existing MCP servers. Its primary purpose is materially different: testing and benchmarking MCP servers via Claude-driven tool use, with support for transports, headers/env vars, XML task parsing, scoring, and report generation. These are substantial functional capabilities not reflected in the declared purpose, so this is a clear mismatch.

Ae1

High
Category
analysis-evasion
Content
- [⚡ TypeScript Guide](./reference/node_mcp_server.md) - TypeScript patterns and examples
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- [⚡ TypeScript Guide](./reference/node_mcp_server.md) - TypeScript patterns and examples
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- [⚡ TypeScript Guide](./reference/node_mcp_server.md) - TypeScript patterns and examples
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

External Model or Provider Selection

High
Category
Excessive Agency
Content
optional arguments:
  -h, --help            Show help message
  -t, --transport       Transport type: stdio, sse, or http (default: stdio)
  -m, --model           Claude model to use (default: claude-3-7-sonnet-20250219)
  -o, --output          Output file for report (default: print to stdout)

stdio options:
Confidence
90% confidence
Finding
Skill selects an external model or provider that may use a different account or billing plan than the operator expects. Undisclosed model switches can cause unexpected cost or quota consumption.

Credential Access

High
Category
Privilege Escalation
Content
**OAuth 2.1**:
- Use secure OAuth 2.1 with certificates from recognized authorities
- Validate access tokens before processing requests
- Only accept tokens specifically intended for your server

**API Keys**:
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding
The skill instructs the agent to perform actions that imply MCP access and file creation/writing, but it does not declare any explicit tool scope such as permissions or allowed-tools. That creates an under-specified trust boundary: a host may grant broader tools than the author intended, enabling the skill to drive sensitive capabilities during execution.

Rp1

Medium
Category
MCP Rug Pull
Confidence
80% confidence
Finding
Using `npx @modelcontextprotocol/inspector` without pinning a version causes execution of whatever package version is current at run time. This introduces a supply-chain risk: a compromised upstream release or breaking update could execute unexpected code or alter testing behavior when users follow the guide.

Unrestricted Tool Access

Medium
Category
Excessive Agency
Content
After understanding the API and tools, USE the MCP server tools:
- Inspect content using READ-ONLY and NON-DESTRUCTIVE operations ONLY
- Goal: identify specific content (e.g., users, channels, messages, projects, tasks) for creating realistic questions
- Should NOT call any tools that modify state
- Will NOT read the code of the MCP server implementation itself
- Parallelize this step with individual sub-agents pursuing independent explorations
- Ensure each subagent is only performing READ-ONLY, NON-DESTRUCTIVE, and IDEMPOTENT operations
Confidence
80% confidence
Finding
Skill grants unrestricted tool access without appropriate constraints. An agent with unfettered tool access can perform arbitrary actions including file modification, network requests, and code execution.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The guide presents a streamable HTTP MCP server example that accepts requests on `/mcp` without any authentication, authorization, or explicit warning that the endpoint is exposed. In the context of an MCP server builder skill, this is dangerous because developers may copy the example verbatim and deploy remote tool execution endpoints that arbitrary clients can invoke.

External Transmission

Medium
Category
Data Exfiltration
Content
mcp = FastMCP("example_mcp")

# Constants
API_BASE_URL = "https://api.example.com/v1"

# Enums
class ResponseFormat(str, Enum):
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
mcp = FastMCP("example_mcp")

# Constants
API_BASE_URL = "https://api.example.com/v1"

# Enums
class ResponseFormat(str, Enum):
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The evaluation prompt explicitly instructs the model to disclose the inputs and outputs of every tool invocation in its <summary>. Since MCP tools often handle secrets, tokens, personal data, internal documents, or privileged API responses, this design can cause sensitive data to be copied into model output and then persisted in the generated report. In an evaluation harness, this is especially risky because logs and reports are commonly shared, stored, or inspected outside the original trust boundary.

Ssd 3

Medium
Confidence
98% confidence
Finding
This is a true data-exposure issue: the system prompt requires the model to reveal full tool inputs and outputs, and the harness then extracts and stores those summaries/feedback in the final report. If the evaluated MCP server accesses external services, the tool I/O may include API keys, authentication headers, customer records, proprietary content, or other confidential material, turning routine evaluation into an exfiltration channel. The skill context increases the danger because this code is specifically meant to test MCP servers that bridge LLMs to external systems, where sensitive data exposure is a realistic and common failure mode.

Intent-Code Divergence

Low
Confidence
96% confidence
Finding
The document explicitly instructs readers to avoid `any` and use proper types or `unknown`, but earlier example code uses `makeApiRequest<any>` and `user: any`, and later the shared utility signature uses `data?: any` and `params?: any`. This is an active contradiction between the guide's stated intent and its demonstrated implementation patterns, not merely an omission.

Missing User Warnings

Low
Confidence
92% confidence
Finding
The guide includes a resource example that reads a local file path derived from user-controlled input (`name`) without any warning or safeguards. In an MCP server-building guide, this can normalize unsafe patterns and lead implementers to create path traversal or unintended local file disclosure primitives.

Unpinned Dependencies

Low
Category
Supply Chain
Content
anthropic>=0.39.0
mcp>=1.1.0
Confidence
98% confidence
Finding
The dependency is specified with a lower bound only (anthropic>=0.39.0), which permits installation of any newer release and makes builds non-reproducible. This increases supply-chain risk and makes it harder to ensure deployment avoids vulnerable or breaking versions, especially relevant for an MCP-building skill that may be reused to create networked integrations.

Unverifiable Dependency: anthropic has 4 known advisory(ies) (CVE-2026-34450 (Claude SDK for Python has Insecure Default File Permissions in Local Filesystem ); CVE-2026-34452 (Claude SDK for Python: Memory Tool Path Validation Race Condition Allows Sandbox); CVE-2026-34450 (The Claude SDK for Python provides access to the Claude API from Python applicat) +1 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
93% confidence
Finding
The manifest references anthropic without pinning a specific release, and the package has known advisories. That means consumers may install an affected version without realizing it, and since this package can interact with local files and external APIs, vulnerable versions may expose filesystem or sandbox-related risk depending on usage.

Unpinned Dependencies

Low
Category
Supply Chain
Content
anthropic>=0.39.0
mcp>=1.1.0
Confidence
99% confidence
Finding
The dependency mcp>=1.1.0 is unpinned, so installations may resolve to different versions over time, including versions with security regressions or incompatible behavior. Because this skill is specifically for building MCP servers that expose external-service tooling, dependency uncertainty is more concerning than in a purely local utility.

Unverifiable Dependency: mcp has 12 known advisory(ies) (CVE-2025-53366 (MCP Python SDK vulnerability in the FastMCP Server causes validation error, lead); CVE-2025-66416 (Model Context Protocol (MCP) Python SDK does not enable DNS rebinding protection); CVE-2026-52870 (MCP Python SDK: Experimental task handlers allow any client to access and cancel) +9 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
96% confidence
Finding
The mcp package has multiple known advisories, but the requirements file does not constrain it to a safe version. In the context of a skill for building MCP servers, this is more dangerous because vulnerable SDK behavior could directly affect exposed tools, request handling, or server-side protections such as validation and network safety controls.

Static analysis

No suspicious patterns detected.