GitHub Advisoryadvisory · npm

GHSA-wcjj-9m6g-2fr2 functype-mcp-server: MCP `set_functype_version` Package Alias RCE via Unsanitized pnpm install + Dynamic Import

HIGH Published 2026-09-09 Modified 2026-11-02 Official page ↗
Aliases
CVE-2026-59176
Ecosystem
npm
Packages
functype-mcp-server
Severity
High
CVSS vector
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Weaknesses
CWE-829
Reviewed
2026-09-09

Affected packages

• npm functype-mcp-server: < 1.4.4 → fixed in 1.4.4

Description

MCP `set_functype_version` Package Alias RCE via Unsanitized pnpm install + Dynamic Import Summary The `set_functype_version` MCP tool in `functype-mcp-server` accepts an unconstrained `version` string, interpolates it directly into an npm package specifier (`functype@`), and installs it via `pnpm add` without any validation. Because npm/pnpm package specifiers support `file:`, `npm:`, and other alias syntaxes, an attacker who can send an MCP `tools/call` request to this tool can cause the server to install an arbitrary local or remote package as `functype`. Immediately after installation, the server calls `initDocsData(true)`, which dynamically imports `functype/cli` from the newly installed location, executing attacker-controlled JavaScript in the MCP server process. This results in full Remote Code Execution (RCE) with the privileges of the server process — full confidentiality, integrity, and availability impact (CVSS 7.8 High). Details The vulnerable code is in `packages/mcp-server/src/index.ts`. The `set_functype_version` tool is registered at line 115 and is enabled by default (no authentication required in stdio mode). Source (user input accepted without validation): ```ts // packages/mcp-server/src/index.ts:119-121 parameters: z.object({ version: z.string().describe('The functype version to install (e.g., "0.46.0", "latest", "^0.45.0")'), }), ``` Only `z.string()` validation is applied — no semver format check, no allowlist for dist-tags, and no rejection of `file:`, `npm:`, URL, or path alias syntaxes. Sink 1 — arbitrary package installation: ```ts // packages/mcp-server/src/index.ts:122-125 execute: async (args) => { const spec = `functype@${args.version}` try { execFileSync("pnpm", ["add", spec], { cwd: PROJECT_ROOT, stdio: "pipe", timeout: 60_000 }) ``` `args.version` is interpolated into the package specifier string and passed directly to `pnpm add`. Supplying `file:/path/to/evil` causes pnpm to install an attacker-controlled directory as the `functype` package alias. Sink 2 — dynamic import executes installed package code: ```ts // packages/mcp-server/src/lib/docs/data.ts:23-30 if (force) { const resolvedPath = require.resolve("functype/cli") cli = await import(`${pathToFileURL(resolvedPath).href}?t=${Date.now()}`) } ``` `initDocsData(true)` is called immediately after installation (line 134 in `index.ts`). It resolves `functype/cli` from the node_modules that now points to the attacker's package and dynamically imports it, executing any module-level code in the attacker's `cli.js` at import time. Data flow summary: 1. `index.ts:115` — MCP tool `set_functype_version` registered, no auth required. 2. `index.ts:119-121` — `version` accepted as raw `z.string()` (source). 3. `index.ts:123` — `functype@${args.version}` constructed without sanitization. 4. `index.ts:125` — `execFileSync("pnpm", ["add", spec], ...)` installs attacker-controlled package (sink: arbitrary install). 5. `index.ts:134` — `initDocsData(true)` called immediately. 6. `data.ts:29-30` — `require.resolve("functype/cli")` + dynamic `import()` executes attacker module (sink: RCE). PoC Step 1 — Prepare the attacker-controlled evil package: ```bash mkdir -p /tmp/evil cat > /tmp/evil/package.json /tmp/evil/cli.js exploit.mjs { + const trimmed = version.trim() + return trimmed === version && SAFE_FUNCTYPE_VERSION.test(trimmed) && !/[/:\\@]/.test(trimmed) +} execute: async (args) => { • const spec = `functype@${args.version}` + if (!isSafeFunctypeVersion(args.version)) { + return "Invalid functype version. Use a semver version, range prefix (^ or ~), or a known dist-tag." + } + const spec = `functype@${args.version}` try { • execFileSync("pnpm", ["add", spec], { cwd: PROJECT_ROOT, stdio: "pipe", timeout: 60_000 }) + execFileSync("pnpm", ["add", "--ignore-scripts", spec], { cwd: PROJECT_ROOT, stdio: "pipe", timeout: 60_000 }) ``` Impact This is a Remote Code Execution (RCE) vulnerability. Any MCP client that can invoke the `set_functype_version` tool — which requires no authentication and is enabled by default in the stdio MCP server — can execute arbitrary JavaScript in the MCP server process. Who is impacted: • Developers and teams running `functype-mcp-server` (version 1.4.3) in their local or CI environments as an AI coding assistant integration. • Users whose AI assistant (LLM agent) is connected to this MCP server and is susceptible to indirect prompt injection: a malicious document or web page read by the AI could trigger a `set_functype_version` call with a `file:` or `npm:` alias payload. • In non-default `TRANSPORT_TYPE=httpStream` deployments, network-accessible attackers can exploit this without local access. The full impact at exploitation is confidentiality, integrity, and availability — an attacker can read secrets from the process environment, modify files, or crash the server. Reproduction artifacts `Dockerfile` ```dockerfile Dockerfile for VULN-001: MCP set_functype_version Package Alias RCE Build context: reports/npmAI_684_jordanburke__functype/ COPY repo/ -> /workspace/functype/ (victim monorepo) COPY vuln-001/ -> supporting PoC files Build: docker build -t vuln001-functype-rce -f vuln-001/Dockerfile . Run: docker run --rm vuln001-functype-rce Expected exit 0 with "[poc] EXPLOIT SUCCEEDED" in output. FROM node:24-slim Install pnpm matching the repo's packageManager field ([email protected]). RUN npm install -g [email protected] --quiet ── Victim workspace ────────────────────────────────────────────────────────── WORKDIR /worksp…

Related

Alias · CVE (1)

  • CVE-2026-59176 Functype is a family of TypeScript functional programming libraries. vulnerability

Weakness · CWE (1)

  • CWE-829 Inclusion of Functionality from Untrusted Control Sphere weakness

References