Back to skill

Security audit

Mcp Dev Toolkit

Security checks for vulnerabilities and agentic risk

Overview

This developer toolkit is not overtly malicious, but its copy-paste examples can create MCP tools with broad file, network, and database access without strong safety boundaries.

Install only if you treat this as a rough developer reference, not a production-safe template. Pin package versions, validate scaffold names, restrict filesystem tools to an explicit workspace, allowlist API destinations, use least-privilege database credentials, and add user confirmation before enabling write or broad data-access tools.

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 (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/scaffold.sh:4
Finding

Command and Generated-Configuration Injection Through an Unvalidated Project Name

Content
View full analysis
}" LANG="${2:?Specify python or typescript}" DIR="$NAME-mcp-server" mkdir -p "$DIR" ``` ```bash sed -i "s/REPLACE_NAME/$NAME/g" "$DIR/server.py" ``` ```bash cat > "$DIR/package.json" <
Remediation
View remediation
&2 exit 1 fi ``` - Generate JSON through a JSON-aware utility or language runtime rather than an interpolated heredoc. - Avoid constructing `sed` programs with untrusted values. Pass the name to a small Python or Node.js template renderer that performs literal replacement. - Canonicalize the destination path and verify that it remains beneath an explicitly selected output directory. - Add tests for quotes, slashes, ampersands, backslashes, newlines, traversal components, and shell metacharacters. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:14
Finding

Unpinned Package Execution and Broad Dependency Version Ranges

Content
View full analysis
=1.0.0 ``` ```json "dependencies": { "@modelcontextprotocol/sdk": "^1.0.0", "zod": "^3.22.0" }, "devDependencies": { "typescript": "^5.3.0", "@types/node": "^20.0.0" } ``` ### Technical Analysis The documented `npx` commands do not specify an exact version. If the package is absent locally, `npx` can retrieve and execute the version currently resolved by the registry. The effective code therefore can change after this Skill has been reviewed. The generated Python and TypeScript manifests also use open or semver-compatible version ranges. No lockfile or integrity data is generated. A future compatible release, compromised publisher release, or compromised registry response could consequently introduce unreviewed code into generated servers. Package installation commonly executes package lifecycle hooks with the privileges of the developer or build agent, making dependency compromise materially different from an ordinary application defect. ### Attack Path 1. A user follows the documented `npx` command or installs dependencies in a generated server. 2. The package manager resolves a version that was not fixed at the time of this audit. 3. A compromised or maliciously changed release is downloaded. 4. Package lifecycle logic or subsequently imported package code executes locally. 5. The malicious dependency obtains the permissions available to the user or CI worker. ### Impact Assessment A compromised dependency could execute commands, alter source or build output, read developer and CI credentials, or tamper with published artifacts. The reachable scope is that of the package-manager process and may include source repo ...[truncated 106 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
references/file-tools.md:5
Finding

Filesystem Tools Permit Access Outside the Intended Workspace

Content
View full analysis
{ const content = await fs.readFile(path, "utf-8"); return { content: [{ type: "text", text: content }] }; }); ``` ```typescript server.tool("write_file", { path: z.string(), content: z.string() }, async ({ path, content }) => { await fs.writeFile(path, content, "utf-8"); return { content: [{ type: "text", text: `Written ${content.length} bytes to ${path}` }] }; }); ``` ```typescript server.tool("search_files", { pattern: z.string().describe("Regex pattern"), path: z.string().default("."), file_type: z.string().optional() }, async ({ pattern, path, file_type }) => { const args = ["--json", pattern, path]; if (file_type) args.push("--type", file_type); const result = await execFile("rg", args); ``` ```typescript server.tool("list_dir", { path: z.string().default("."), recursive: z.boolean().default(false) }, async ({ path, recursive }) => { const entries = recursive ? await glob("**/*", { cwd: path }) : await fs.readdir(path); return { content: [{ type: "text", text: entries.join("\n") }] }; }); ``` ### Technical Analysis All file operations accept caller-controlled paths. The examples explicitly permit absolute or relative paths but do not define an authorized workspace root or perform path canonicalization, traversal rejection, or symlink containment checks. Because MCP tools are intended to be invoked by an agent, untrusted prompt content may influence their arguments. The tool process consequently becomes a confused deputy: a remote or indirect caller can request filesystem operations using the local account's privileges. Using `execFile` for ripgrep avoids shell metacharacter injecti ...[truncated 1081 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
references/api-tools.md:5
Finding

Arbitrary API Destinations Enable Server-Side Request Forgery

Content
View full analysis
{ const resp = await fetch(url, { headers: { "Accept": "application/json", ...extraHeaders } }); const data = await resp.json(); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] }; }); ``` ```typescript server.tool("api_post", { url: z.string(), body: z.record(z.any()), headers: z.record(z.string()).optional() }, async ({ url, body, headers: extraHeaders }) => { const resp = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json", ...extraHeaders }, body: JSON.stringify(body) }); const data = await resp.json(); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] }; }); ``` ```typescript server.tool("graphql_query", { endpoint: z.string(), query: z.string().describe("GraphQL query string"), variables: z.record(z.any()).optional() }, async ({ endpoint, query, variables }) => { const resp = await fetch(endpoint, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ query, variables }) }); ``` ### Technical Analysis The request destination is fully controlled by the MCP caller. There is no restriction on URL scheme, hostname, port, resolved IP address, or redirect target. This allows the MCP server to be used as a network proxy to resources reachable from its execution environment. Potential targets include loopback services, private network addresses, link-local cloud metadata services, and administrative endpoints not directly reachable by the caller. Returning parsed response bodies through MCP creates a direct disclosure channel. Caller ...[truncated 1137 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
references/database-tools.md:10
Finding

SQL Prefix Check Does Not Enforce Read-Only Database Access

Content
View full analysis
{ // Safety: only allow SELECT if (!sql.trim().toUpperCase().startsWith("SELECT")) { return { content: [{ type: "text", text: "Error: Only SELECT queries allowed" }] }; } const result = await pool.query(sql); return { content: [{ type: "text", text: JSON.stringify(result.rows, null, 2) }] }; }); ``` ```python @server.tool("sqlite_query") async def sqlite_query(sql: str) -> str: """Execute a SQL query against the SQLite database.""" if not sql.strip().upper().startswith("SELECT"): return "Error: Only SELECT queries allowed" conn = sqlite3.connect(os.environ.get("SQLITE_PATH", "data.db")) cursor = conn.execute(sql) rows = [dict(zip([d[0] for d in cursor.description], row)) for row in cursor.fetchall()] conn.close() return json.dumps(rows, indent=2) ``` ### Technical Analysis Checking whether SQL text starts with `SELECT` is not equivalent to parsing the statement or enforcing read-only execution. In PostgreSQL, a `SELECT` can invoke functions with side effects or access any table and function permitted to the connection role. Depending on driver and server configuration, appended statements may also create a multi-statement execution path. The same pattern in the SQLite example permits unrestricted reads of every object available in the selected database. Although Python's standard `sqlite3.execute` generally rejects multiple statements, the prefix check still does not constitute an authorization policy and does not limit which data can be selected. The tool exposes arbitrary query capability to an MCP caller and relies on application string inspection rather than database-enforced least privil ...[truncated 833 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
Findings (9)

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding

Using npx @anthropic/mcp-cli without pinning an exact version causes the latest published package to be fetched and executed at runtime. If the upstream package is compromised, unexpectedly changed, or a breaking release is published, users of the skill may run unreviewed code on their systems, which is especially risky because this command is presented as a primary setup path for creating MCP servers.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding

The inspection command also invokes npx @anthropic/mcp-cli without a pinned version, so running tests may download and execute whatever version is current at that moment. In a developer-tooling skill, this expands supply-chain exposure because users are encouraged to run the command locally during validation, increasing the chance of executing compromised or incompatible code.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The examples define MCP tools that make arbitrary outbound HTTP requests using user-controlled URLs, headers, GraphQL queries, and request bodies, but the surrounding documentation does not warn that using these patterns can exfiltrate data or reach internal services. In an agent-tooling context, this is dangerous because developers may copy these patterns directly into production tools, enabling SSRF, unauthorized data transmission, or use of attacker-supplied authentication headers without realizing the security implications.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This markdown file describes a tool that writes arbitrary content to a filesystem path, but it does not warn users that invoking it will modify existing files or create new ones. Because markdown files should disclose behaviors affecting user data or system integrity, the omission is a safety-relevant documentation gap.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This markdown file contains code examples that read sensitive connection data from environment variables, such as DATABASE_URL. While the operation is common for database tooling, the surrounding documentation does not warn users that credentials or connection details will be sourced from the environment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The PostgreSQL example accepts SQL input and transmits it to a database server via pool.query, but the markdown does not explicitly disclose that queries and returned data will be sent to and retrieved from a live database. For documentation files, user-facing warnings are expected when behavior could affect privacy or external systems.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The SQLite example reads the database path from SQLITE_PATH and executes queries against a local file, which can access local user or application data. The markdown lacks any caution that this behavior reads from the local filesystem and may expose sensitive records.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The MongoDB example queries a collection and returns matching documents, but the documentation does not warn that this may access and reveal potentially sensitive data from a remote database. Markdown skill documentation should disclose privacy- or system-impacting behavior when presenting such patterns.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The documented search_files example invokes an external command via execFile("rg", args), which is subprocess execution. In this markdown description there is no warning or note that the tool shells out to a local binary, which is behavior that can affect system expectations and should be disclosed.

Content

No source excerpt is available for this finding.