Back to skill

Security audit

Agentic MCP Server Builder

Security checks for vulnerabilities and agentic risk

Overview

This skill is a plausible MCP scaffolding helper, but its bundled script can overwrite arbitrary writable files if given unsafe paths.

Install only if you are comfortable with a scaffolding helper that can create and overwrite local files. Use dry-run for review first, choose output and scaffold paths inside a disposable workspace, avoid the outside-workspace option unless necessary, and inspect for existing files or symlinks before materializing the scaffold.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/scaffold_mcp_server.py:144
Finding
Unrestricted Output Path Allows Arbitrary File Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `scripts/scaffold_mcp_server.py`, lines 55-91 and 144 **Vulnerability Type**: Unrestricted file write and unsafe overwrite **Risk Level**: Medium ### Vulnerable Code ```python def render(result: dict, output_path: Path, fmt: str) -> None: output_path.parent.mkdir(parents=True, exist_ok=True) if fmt == "json": output_path.write_text(json.dumps(result, indent=2), encoding="utf-8") return if fmt == "md": lines = [ f"# {result['summary']}", "", f"- status: {result['status']}", "", "## Planned Files", ] for item in result["details"]["file_map"]: lines.append(f"- {item}") lines.extend(["", "## Tools"]) for tool in result["details"]["tools"]: lines.append(f"- {tool['name']}: {tool['description']}") output_path.write_text("\n".join(lines) + "\n", encoding="utf-8") return with output_path.open("w", newline="", encoding="utf-8") as handle: writer = csv.writer(handle) writer.writerow(["name", "description"]) for tool in result["details"]["tools"]: writer.writerow([tool["name"], tool["description"]]) ``` The unchecked path is passed to this function at line 144: ```python render(result, Path(args.output), args.format) ``` ### Technical Analysis The required `--output` argument is converted directly into a `Path` and passed to `render()`. Unlike `scaffold_root`, the output path is not resolved and checked against the current workspace. All supported output formats use operations that create or truncate the destination: - `Path.write_text()` truncates an existing file. - `Path.open("w")` truncates an existing file. - `mkdir(parents=True, exist_ok=True)` creates attacker-selected parent directories where process permissions permit. The write operations also follow symbolic links. Consequently, an output pa ...[truncated 1236 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Resolve `--output` and enforce workspace containment before creating directories or files: ```python output_path = resolve_path_in_workspace( Path(args.output), workspace_root, "output", args.allow_outside_workspace, ) ``` 2. Do not reuse the scaffold override implicitly. Prefer a separate, explicit option such as `--allow-output-outside-workspace` if external report output is genuinely required. 3. Reject symbolic links in the destination and its existing parent components. Where supported, use descriptor-relative operations and no-follow flags to mitigate time-of-check/time-of-use races. 4. Avoid silently truncating existing files. Open destinations in exclusive creation mode (`"x"`) by default and require an explicit `--force` option to overwrite. 5. Revalidate the resolved destination immediately before writing. 6. Write to a securely created temporary file in the validated destination directory and atomically replace the final path only after all checks succeed. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/scaffold_mcp_server.py:94
Finding
Scaffold Workspace Restriction Can Be Bypassed Through Symbolic Links<![CDATA[ ## Vulnerability Details **File Location**: `scripts/scaffold_mcp_server.py`, lines 94-106 **Vulnerability Type**: Symlink-following file write and unsafe overwrite **Risk Level**: Medium ### Vulnerable Code ```python def maybe_write_scaffold(root: Path, file_map: list[str], dry_run: bool) -> None: if dry_run: return for relative_path in file_map: path = root / relative_path path.parent.mkdir(parents=True, exist_ok=True) if path.suffix == ".py": path.write_text("# Starter file\n", encoding="utf-8") elif path.suffix == ".json": path.write_text("{}\n", encoding="utf-8") else: path.write_text("# Starter document\n", encoding="utf-8") ``` The scaffold root is resolved before this function is called, but individual destination files are not resolved or checked again: ```python scaffold_root = resolve_path_in_workspace( raw_scaffold_root, workspace_root, "scaffold_root", args.allow_outside_workspace, ) maybe_write_scaffold(scaffold_root, file_map, args.dry_run) ``` ### Technical Analysis The script validates the resolved scaffold root against the workspace, but it subsequently appends fixed relative paths and writes to them without checking whether any destination or intermediate directory is a symbolic link. Python's `Path.write_text()` follows symbolic links and truncates existing targets. Therefore, validating only the root does not guarantee that the eventual write remains under that root. An attacker who can prepare files in the workspace can place a symlink at a generated destination such as `server.py`, `tool_registry.py`, `schemas/tools.json`, or `README.md`. The scaffold operation then follows that link to an external target. The same operations overwrite ordinary existing project files without warning, even when no symlink is involved. ### Attack Path 1. An attacker predicts or controls the scaffold directory through the JSON `sc ...[truncated 1105 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Check every scaffold destination, not only the root. Resolve each destination and verify that it remains beneath the validated scaffold root and workspace. 2. Reject symbolic links at the final destination and in every existing intermediate path component. 3. Use no-follow file-opening behavior where the operating system supports it, preferably with directory file descriptors to reduce symlink race conditions. 4. Create files exclusively by default rather than truncating them: ```python with path.open("x", encoding="utf-8") as handle: handle.write(content) ``` 5. Require an explicit `--force` option before replacing an existing regular file. 6. Recheck containment and file type immediately before each write because a separate check followed by a write can be vulnerable to a time-of-check/time-of-use race. 7. Add automated tests covering final-component symlinks, symlinked intermediate directories, pre-existing files, and destinations outside the workspace. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (5)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description understates the skill's real behavior: the implementation can write scaffold files and may support paths outside the workspace, while the described validation/checking capability is not actually implemented. This mismatch is dangerous because users and orchestrators may grant trust based on a narrower stated purpose, enabling stronger side effects than expected and potentially causing unauthorized file creation or overwrite.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill advertises operational behavior that reads and writes files, but it does not declare an explicit tool scope such as permissions or allowed-tools. This creates an authorization ambiguity where an agent may invoke file-capable tooling more broadly than a user expects, increasing the risk of unintended filesystem access during scaffolding.

Missing User Warnings

Low
Confidence
93% confidence
Finding
The workflow notes that starter files may be materialized, but it does not clearly warn that running the skill can create or modify files in the workspace. While less severe than unrestricted path handling, this omission can still lead to surprising side effects, accidental overwrites, or unsafe use in automated contexts where users assume analysis-only behavior.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The render function creates parent directories and writes the output artifact in JSON, Markdown, or CSV format, but does not emit any user-visible warning or status message. For a code-file audit under this rule, filesystem writes should have some disclosure such as logging, printing, or documented warning text.

Missing User Warnings

Low
Confidence
88% confidence
Finding
This code creates directories and writes multiple files to disk when dry-run is not enabled. Although the behavior is the tool's purpose, the implementation provides no print/log message, confirmation prompt, or inline comment/docstring disclosing that scaffold files will be created at the target path.

Static analysis

No suspicious patterns detected.