Back to skill

Security audit

building-mcp-servers

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate MCP server-building guide, but some examples could lead users to create unsafe servers if copied directly.

Install only if you are comfortable reviewing and hardening generated MCP server code. Pin package versions before running commands, avoid copying the file-resource and credential-prompt examples without validation and secret-handling safeguards, and require explicit authorization checks before implementing destructive tools.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
references/python_mcp_server.md:532
Finding

Path Traversal in Document Resource Example

Content
View full analysis

Vulnerability Details

File Location: references/python_mcp_server.md, lines 532–542
Vulnerability Type: Path traversal leading to arbitrary local file disclosure
Risk Level: Medium

Vulnerable Code

python
@mcp.resource("file://documents/{name}")
async def get_document(name: str) -> str:
    '''Expose documents as MCP resources.

    Resources are useful for static or semi-static data that doesn't
    require complex parameters. They use URI templates for flexible access.
    '''
    document_path = f"./docs/{name}"
    with open(document_path, "r") as f:
        return f.read()

Technical Analysis

The resource parameter name is controlled by the MCP client and is directly interpolated into a filesystem path. The implementation does not reject absolute paths or .. traversal components, canonicalize the resulting path, or verify that it remains under the intended ./docs directory.

If an MCP server is generated using this documented implementation, an untrusted client can supply a value such as ../../.env. The resulting path escapes the document root and is passed to open(). This crosses the trust boundary between a remote or otherwise untrusted MCP client and the server's local filesystem.

The issue is an insecure instructional coding pattern rather than evidence of intentional malicious behavior.

Attack Path

  1. A developer uses the documented resource implementation in an MCP server.
  2. The server exposes file://documents/{name} to an untrusted MCP client.
  3. The attacker requests a crafted resource name containing traversal components, such as ../../.env.
  4. The server constructs ./docs/../../.env without validation.
  5. open() resolves the traversal and reads the target if the server process has permission.
  6. The file contents are returned through the MCP resource response.

Impact Assessment

An attacker can read files available to the MCP server process outside the intended document directory. De ...[truncated 379 chars]

Remediation
View remediation

Remediation Suggestions

  • Resolve requested files against a fixed canonical document root.
  • Reject absolute paths, traversal components, null bytes, and malformed names.
  • Verify after resolution that the candidate remains beneath the canonical document root.
  • Account for symbolic-link escapes or disallow symlinks where appropriate.
  • Prefer opaque document identifiers mapped to an allowlist of known files rather than accepting filesystem paths.
  • Apply equivalent validation in every generated resource implementation.

Example hardening pattern:

python
from pathlib import Path

DOCUMENT_ROOT = Path("./docs").resolve()

@mcp.resource("file://documents/{name}")
async def get_document(name: str) -> str:
    candidate = (DOCUMENT_ROOT / name).resolve()

    if candidate == DOCUMENT_ROOT or DOCUMENT_ROOT not in candidate.parents:
        raise ValueError("Invalid document path")

    if not candidate.is_file():
        raise FileNotFoundError("Document not found")

    return candidate.read_text(encoding="utf-8")

For stronger isolation, map validated identifiers to predefined paths and ensure the server process runs with minimal filesystem privileges.

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 Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (33)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 82)May include surrounding context.

md
- [⚡ TypeScript Guide](./references/node_mcp_server.md) - TypeScript patterns and examples

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 109)May include surrounding context.

md
- [⚡ TypeScript Guide](./references/node_mcp_server.md) - TypeScript patterns and examples

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 260)May include surrounding context.

md
- [⚡ TypeScript Guide](./references/node_mcp_server.md) - TypeScript patterns and examples

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/dotnet_mcp_v2.md (reported line 379)May include surrounding context.

md
Cross-application SSO is supported via the **Identity Assertion Authorization Grant (ID-JAG)**
flow: `IdentityAssertionGrantProvider` performs the RFC 8693 token exchange at the enterprise IdP
and the RFC 7523 JWT bearer grant at the MCP authorization server, caching the access token until
expiry (`InvalidateCache()` to force re-auth).

---

External Model or Provider Selection

High
Category
Excessive Agency
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.

Content

Scanner excerpt · references/evaluation.md (reported line 488)May include surrounding context.

md
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:

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/mcp_best_practices.md (reported line 158)May include surrounding context.

md
**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**:

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/transport-and-auth.md (reported line 262)May include surrounding context.

md
**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**:

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/transport-and-auth.md (reported line 256)May include surrounding context.

md
### Token Refresh Handling

Access tokens are short-lived (typically 1 hour). Strategies:

1. **Client-side refresh:** Clients refresh tokens before expiration and reconnect
2. **Proactive server refresh:** Background task refreshes tokens expiring soon

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The 'When to Use' section explicitly says the skill applies when the user asks or mentions it in English or Portuguese. This imposes a language constraint in natural-language instructions, but the file does not offer opt-in language choice or explain why the skill must be restricted to those languages.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding

The skill instructs users to run npx @modelcontextprotocol/inspector without pinning a version, which can pull whatever package version is current at execution time. That creates a supply-chain and reproducibility risk: a future compromised, breaking, or malicious release could be executed implicitly during testing.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding

This repeated unpinned npx @modelcontextprotocol/inspector invocation has the same risk profile: it executes a remotely resolved package version at runtime. In a skill focused on building MCP servers, users are especially likely to copy-paste commands directly, increasing the chance of unintended execution of a changed or malicious package.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/dotnet_mcp_server.md (reported line 228)May include surrounding context.

md
{
            // Make API request using injected HttpClient
            var response = await http.GetAsync(
                $"https://api.example.com/v1/users/search?q={Uri.EscapeDataString(query)}&limit={limit}&offset={offset}",
                ct);

            response.EnsureSuccessStatusCode();

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/dotnet_mcp_server.md (reported line 424)May include surrounding context.

md
{
            // Make API request using injected HttpClient
            var response = await http.GetAsync(
                $"https://api.example.com/v1/users/search?q={Uri.EscapeDataString(query)}&limit={limit}&offset={offset}",
                ct);

            response.EnsureSuccessStatusCode();

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/dotnet_mcp_server.md (reported line 464)May include surrounding context.

md
{
            // Make API request using injected HttpClient
            var response = await http.GetAsync(
                $"https://api.example.com/v1/users/search?q={Uri.EscapeDataString(query)}&limit={limit}&offset={offset}",
                ct);

            response.EnsureSuccessStatusCode();

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/dotnet_mcp_server.md (reported line 507)May include surrounding context.

md
{
            // Make API request using injected HttpClient
            var response = await http.GetAsync(
                $"https://api.example.com/v1/users/search?q={Uri.EscapeDataString(query)}&limit={limit}&offset={offset}",
                ct);

            response.EnsureSuccessStatusCode();

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/dotnet_mcp_server.md (reported line 639)May include surrounding context.

md
{
            // Make API request using injected HttpClient
            var response = await http.GetAsync(
                $"https://api.example.com/v1/users/search?q={Uri.EscapeDataString(query)}&limit={limit}&offset={offset}",
                ct);

            response.EnsureSuccessStatusCode();

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/dotnet_mcp_server.md (reported line 650)May include surrounding context.

md
{
            // Make API request using injected HttpClient
            var response = await http.GetAsync(
                $"https://api.example.com/v1/users/search?q={Uri.EscapeDataString(query)}&limit={limit}&offset={offset}",
                ct);

            response.EnsureSuccessStatusCode();

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/dotnet_mcp_server.md (reported line 766)May include surrounding context.

md
{
            // Make API request using injected HttpClient
            var response = await http.GetAsync(
                $"https://api.example.com/v1/users/search?q={Uri.EscapeDataString(query)}&limit={limit}&offset={offset}",
                ct);

            response.EnsureSuccessStatusCode();

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/node_mcp_server.md (reported line 601)May include surrounding context.

md
{
            // Make API request using injected HttpClient
            var response = await http.GetAsync(
                $"https://api.example.com/v1/users/search?q={Uri.EscapeDataString(query)}&limit={limit}&offset={offset}",
                ct);

            response.EnsureSuccessStatusCode();

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/python_mcp_server.md (reported line 353)May include surrounding context.

md
{
            // Make API request using injected HttpClient
            var response = await http.GetAsync(
                $"https://api.example.com/v1/users/search?q={Uri.EscapeDataString(query)}&limit={limit}&offset={offset}",
                ct);

            response.EnsureSuccessStatusCode();

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/dotnet_mcp_server.md (reported line 1058)May include surrounding context.

bash
dotnet pack -c Release
dotnet nuget push bin/Release/*.nupkg --api-key <key> --source https://api.nuget.org/v3/index.json
json

Unrestricted Tool Access

Medium
Category
Excessive Agency
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.

Content

Scanner excerpt · references/evaluation.md (reported line 205)May include surrounding context.

md
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

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The guide shows a tool using ctx.elicit(..., input_type="password") to request an API key from the user, but provides no guidance on secure handling, storage, redaction, scope limitation, or avoiding logging/exfiltration. In a skill specifically intended to help build MCP servers exposed to LLMs, this can normalize unsafe credential-collection patterns and lead downstream implementers to capture or misuse secrets insecurely.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/quick-start.md (reported line 198)May include surrounding context.

md
[Description("City name")] string city,
        CancellationToken ct)
    {
        var data = await http.GetStringAsync($"https://api.weather.example/{city}", ct);
        return data;
    }
}

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The Python example documents delete_user as requiring admin:write scope, but the tool implementation performs deletion without any visible authorization check. In a skill about building MCP servers that expose tools to LLMs, this is dangerous because developers may copy the example and accidentally ship a privileged destructive tool with no effective per-tool authorization enforcement.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.