Command Injection Vulnerability in website-downloader
1) CNA / Submission Type
- Submission type: Report a vulnerability (CVE ID request)
- Reporter role: Independent security researcher
- Report date: Apr 17, 2026
2) Reporter Contact
- Reporter name:
BruceJin
- Reporter email:
brucejin@zju.edu.cn
- Permission to share contact with vendor:
Yes
3) Vendor / Product Identification
4) Vulnerability Type
- CWE: CWE-78 (Improper Neutralization of Special Elements used in an OS Command)
- Short title: Command injection in MCP
download_website tool handling
5) Affected Versions
- Confirmed affected: 0.1.0, commit
5b399bebad1800ac6df5052b63eaea37117092b6
- Suspected affected range: revisions containing the same request-to-sink flows listed below
- Fixed version: Not available at time of report
6) Vulnerability Description
A command injection vulnerability (CWE-78) has been identified in website-downloader version 0.1.0, specifically within the download_website MCP tool in src/index.ts. The tool constructs a wget command by concatenating user‑supplied url and outputPath arguments into a shell command string and executes it via child_process.exec without proper escaping or argument separation. An attacker with network access to the MCP interface can inject shell metacharacters through outputPath (e.g., ; id #) to execute arbitrary operating system commands with the privileges of the server process, leading to full host compromise, including data exposure, integrity loss, and service disruption. No fixed version is available at the time of reporting.
7) Technical Root Cause
js/command-injection-from-request
- Source:
src/index.ts:83 (request.params.arguments)
- Sink:
src/index.ts:122
- Sink code:
const { stdout, stderr } = await execAsync(wgetCommand);
- Unsafe command construction:
src/index.ts:110: const wgetCommand = [...].join(' ');
src/index.ts:118: '--directory-prefix=' + outputPath
src/index.ts:119: url
8) Attack Prerequisites
- Attacker can invoke the MCP
download_website tool.
- The server process can execute
wget and shell commands through child_process.exec.
- No effective runtime policy strips shell metacharacters from
outputPath or replaces shell execution with argument-vector execution.
- The injected command runs with the privileges of the MCP server process.
9) Proof of Concept / Reproduction Guidance
This proof of concept provides a concise, CVE-style reproduction example for the reported issue.
- Reproduction request
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"download_website","arguments":{"url":"http://127.0.0.1:9/","outputPath":"/tmp/wd-poc; id #","depth":0}}}
- Validation
- Build and start the affected MCP server with
npm run build followed by npm run inspector, or connect mcp-inspector directly to build/index.js.
- Invoke the
download_website tool with the arguments shown above.
- Confirm that the
mcp-inspector response contains output from the injected id command, such as uid=... gid=....
- The reproduction has been manually confirmed by injecting
id and observing the id command result in mcp-inspector.
10) Security Impact
- Confidentiality: High (arbitrary command execution can read files and environment variables accessible to the server process).
- Integrity: High (arbitrary command execution can modify files or application state accessible to the server process).
- Availability: High (arbitrary command execution can terminate processes, delete files, or consume system resources).
- Scope: Changed.
11) CVSS v3.1 Suggestion
- Suggested vector:
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
- Suggested base score: 9.9 (Critical)
- Adjust
PR to N if the affected MCP tool is exposed to unauthenticated remote clients.
12) Workarounds / Mitigations
- Do not expose the MCP server to untrusted clients until a fix is available.
- Restrict access to the
download_website tool to trusted local users only.
- Reject shell metacharacters in
url and outputPath as a temporary defense-in-depth measure.
- Run the MCP server with a dedicated low-privilege OS account and a restricted working directory.
13) Recommended Fix
- Replace
child_process.exec with child_process.execFile or spawn using an argument array and shell: false.
- Pass
wget options as separate arguments instead of building a single shell command string.
- Validate
url with strict scheme and hostname checks.
- Normalize and constrain
outputPath to an intended download directory.
- Add regression tests proving that payloads such as
; id #, && id, backticks, $(), and embedded quotes cannot execute additional commands.
- Publish a maintainer security advisory once a patch is released.
14) References
15) Credits
- Discoverer:
BruceJin
- Discovery method: Static analysis (CodeQL), repository source-code audit, and manual reproduction with
mcp-inspector
16) Additional Notes for Form Mapping
- Audit verdict: Manually reproduced: attacker-controlled MCP tool argument reaches an OS command sink and executes injected shell commands.
- Dynamic exploit replay status: completed with injected
id command; mcp-inspector displayed the id command result.
- Maintainer should validate release mapping before coordinated disclosure.
For furthermore information, please refer to BruceJqs/public_exp#31
Command Injection Vulnerability in website-downloader
1) CNA / Submission Type
2) Reporter Contact
BruceJinbrucejin@zju.edu.cnYes3) Vendor / Product Identification
src/index.ts4) Vulnerability Type
download_websitetool handling5) Affected Versions
5b399bebad1800ac6df5052b63eaea37117092b66) Vulnerability Description
A command injection vulnerability (CWE-78) has been identified in website-downloader version 0.1.0, specifically within the download_website MCP tool in src/index.ts. The tool constructs a wget command by concatenating user‑supplied url and outputPath arguments into a shell command string and executes it via child_process.exec without proper escaping or argument separation. An attacker with network access to the MCP interface can inject shell metacharacters through outputPath (e.g., ; id #) to execute arbitrary operating system commands with the privileges of the server process, leading to full host compromise, including data exposure, integrity loss, and service disruption. No fixed version is available at the time of reporting.
7) Technical Root Cause
js/command-injection-from-requestsrc/index.ts:83(request.params.arguments)src/index.ts:122const { stdout, stderr } = await execAsync(wgetCommand);src/index.ts:110:const wgetCommand = [...].join(' ');src/index.ts:118:'--directory-prefix=' + outputPathsrc/index.ts:119:url8) Attack Prerequisites
download_websitetool.wgetand shell commands throughchild_process.exec.outputPathor replaces shell execution with argument-vector execution.9) Proof of Concept / Reproduction Guidance
This proof of concept provides a concise, CVE-style reproduction example for the reported issue.
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"download_website","arguments":{"url":"http://127.0.0.1:9/","outputPath":"/tmp/wd-poc; id #","depth":0}}}npm run buildfollowed bynpm run inspector, or connectmcp-inspectordirectly tobuild/index.js.download_websitetool with the arguments shown above.mcp-inspectorresponse contains output from the injectedidcommand, such asuid=... gid=....idand observing theidcommand result inmcp-inspector.10) Security Impact
11) CVSS v3.1 Suggestion
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:HPRtoNif the affected MCP tool is exposed to unauthenticated remote clients.12) Workarounds / Mitigations
download_websitetool to trusted local users only.urlandoutputPathas a temporary defense-in-depth measure.13) Recommended Fix
child_process.execwithchild_process.execFileorspawnusing an argument array andshell: false.wgetoptions as separate arguments instead of building a single shell command string.urlwith strict scheme and hostname checks.outputPathto an intended download directory.; id #,&& id, backticks,$(), and embedded quotes cannot execute additional commands.14) References
src/index.ts15) Credits
BruceJinmcp-inspector16) Additional Notes for Form Mapping
idcommand;mcp-inspectordisplayed theidcommand result.For furthermore information, please refer to BruceJqs/public_exp#31