May 9, 2026·7 min read·26 visits
The `@profullstack/mcp-server` package (versions <= 1.4.12) is vulnerable to unauthenticated OS Command Injection. The `domain_lookup` module unsafely concatenates user-supplied input into a shell command, enabling remote code execution.
A critical unauthenticated OS Command Injection vulnerability (CWE-78) exists in the `@profullstack/mcp-server` npm package, specifically within the `domain_lookup` module. The vulnerability allows remote attackers to execute arbitrary commands on the host system via crafted HTTP requests.
The @profullstack/mcp-server package provides a modular server architecture for the Model Context Protocol (MCP). The software utilizes various modules to extend functionality. The domain_lookup module, designed to check domain availability, relies on the external tldx command-line utility to perform these queries.
The vulnerability manifests as a severe OS Command Injection (CWE-78) flaw within this module. The application exposes unauthenticated HTTP POST endpoints (/domain-lookup/check and /domain-lookup/bulk) that accept JSON payloads. These payloads contain user-supplied arrays of domain names or search keywords.
The server fails to sanitize or validate these inputs before processing them. The unvalidated inputs propagate directly to the underlying operating system shell, creating a highly permissive attack surface. Any network-adjacent or remote attacker capable of routing HTTP traffic to the application port (default 3000) can exploit this condition.
The root cause of this vulnerability lies in the improper handling of user input during shell command construction within mcp_modules/domain_lookup/src/service.js. The buildTldxCommand function is responsible for assembling the command string passed to the operating system.
The function constructs this shell command by directly concatenating user-supplied input (domains or keywords) into a single string. It utilizes JavaScript template literals and the .join(' ') method to append the array contents directly after the tldx binary invocation. The software performs no input validation, escaping, or parameterization on this data prior to concatenation.
Following construction, the application passes this unsanitized string to execAsync(). In Node.js, child_process.exec (and its asynchronous wrappers) spawns a system shell (/bin/sh on Unix-like systems, cmd.exe on Windows) to parse and execute the command string. Because the string is interpreted by a shell environment, any included shell metacharacters are evaluated according to the shell's syntactic rules.
This architectural pattern violates the principle of secure command invocation. By utilizing a shell interpreter rather than passing arguments directly to the binary executable via an array, the software allows the input context to shift from data to executable control instructions.
The vulnerable code path initiates in the buildTldxCommand function. The function takes the user-provided array, joins the elements with spaces, and interpolates them directly into the shell command string.
// Vulnerable Implementation
buildTldxCommand(keywords, options = {}) {
// Direct concatenation of user input 'keywords' into the command string
let command = `tldx ${keywords.join(' ')}`;
if (options.prefixes?.length) {
command += ` --prefixes ${options.prefixes.join(',')}`;
}
return command;
}The constructed command string is subsequently passed to the checkDomainAvailability method. This method acts as the execution sink, invoking execAsync(command). Because the string contains user-controlled metacharacters, the underlying shell interprets them as secondary commands rather than literal arguments to tldx.
// Execution Sink
async checkDomainAvailability(domains, options = {}) {
try {
const command = this.buildTldxCommand(domains, options);
// Sink: execAsync interprets shell metacharacters
const { stdout, stderr } = await execAsync(command);
// ...The fundamental fix requires decoupling the user input from shell evaluation. The remediation replaces child_process.exec with child_process.spawn or child_process.execFile. These functions accept the executable path as a discrete argument and the parameters as a dedicated array. The operating system handles argument passing directly to the target process, bypassing shell tokenization entirely.
// Recommended Remediation
const { spawn } = require('child_process');
async checkDomainAvailability(domains, options = {}) {
try {
// Bypasses shell interpretation by passing arguments as an array
const child = spawn('tldx', domains);
// ... handle stdout/stderr eventsExploitation requires no authentication and minimal network prerequisites. An attacker only needs the ability to send HTTP POST requests to an exposed instance of @profullstack/mcp-server. The server commonly binds to 0.0.0.0 on port 3000, making it accessible across local networks or the public internet depending on deployment configurations.
The attack vector involves crafting a specific JSON payload directed at either /domain-lookup/check or /domain-lookup/bulk. The attacker embeds shell control operators (such as ;, |, &, or $()) within the domains or keywords array. These operators instruct the shell environment to terminate the preceding tldx command and begin executing the injected instruction sequence.
The following proof-of-concept demonstrates exploitation via the /domain-lookup/check endpoint. The payload terminates the intended domain lookup with a semicolon, executes the echo command to write a file to the /tmp directory, and neutralizes any trailing application-appended arguments using a hash character (#) as a shell comment.
curl -X POST http://<target>:3000/domain-lookup/check \
-H 'Content-Type: application/json' \
-d '{"domains":["example.com; echo RCE_CONFIRMED > /tmp/rce.txt; #"]}'Execution of this payload results in the application constructing the command string tldx example.com; echo RCE_CONFIRMED > /tmp/rce.txt; #. The /bin/sh interpreter parses this string sequentially, launching tldx against example.com, followed immediately by the attacker's echo command. The server process executes the injected command with the privileges of the Node.js runtime environment.
Successful exploitation of this vulnerability yields full, unauthenticated Remote Code Execution (RCE) on the host operating system. The attacker executes commands within the context and privilege level of the user account running the Node.js application process.
The vulnerability compromises the confidentiality of the system. An attacker can read arbitrary files accessible to the application user, including source code, configuration files, environment variables, database credentials, and cryptographic keys. This data exfiltration enables extensive lateral movement across connected network environments.
Integrity and availability are similarly compromised. The attacker possesses the capability to modify system state, alter application data, install persistent backdoor mechanisms, or deploy secondary malware payloads. Furthermore, the attacker can terminate the server process entirely or consume system resources to induce a denial-of-service condition.
The CVSS v3.1 base score of 9.8 reflects the severity of this flaw. The metrics confirm a network-based attack vector, low attack complexity, no required privileges, and no requisite user interaction. The lack of authentication combined with arbitrary code execution represents the maximum theoretical impact for a software vulnerability.
Organizations utilizing @profullstack/mcp-server must immediately upgrade their deployments to a patched version once released by the maintainers. Vulnerable versions encompass all releases up to and including 1.4.12. Administrators should monitor package repositories for the official update addressing GHSA-v6wj-c83f-v46x.
Developers must replace instances of child_process.exec or execAsync with child_process.spawn or child_process.execFile when handling externally influenced data. Passing arguments as an array directly to the system kernel neutralizes command injection attacks, as the input is never evaluated by a shell interpreter. This architectural change eliminates the CWE-78 vulnerability class entirely for this code path.
Applications should implement strict input validation on all user-supplied data. For domain names, developers should enforce a strict allowlist regex conforming to RFC 1035, permitting only alphanumeric characters, dots, and hyphens. Rejecting any input containing shell metacharacters provides a strong defense-in-depth measure.
Administrators should enforce the Principle of Least Privilege by running the Node.js process as a dedicated, unprivileged service account rather than root. Additionally, implementing global authentication middleware restricts access to the modular endpoints, drastically reducing the accessible attack surface.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
@profullstack/mcp-server profullstack | <= 1.4.12 | - |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-78 |
| Attack Vector | Network |
| CVSS Score | 9.8 (Critical) |
| Impact | Arbitrary Remote Code Execution |
| Exploit Status | Proof of Concept Available |
| Privileges Required | None |
The software constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.
A path traversal vulnerability exists in the S3 emulation layer of rclone when executing the 'serve s3' subcommand. Because the application maps client-supplied S3 object keys containing relative directory sequences to file paths without proper boundary checks, an attacker can escape the logical containment of a target bucket. This enables unauthorized reading, writing, and deletion of files at the root level of the served storage directory.
A critical security flaw was identified in rclone before version 1.75.0, where the custom S3 redirect handler failed to sanitize sensitive authentication headers and encryption keys during cross-host redirects or transport downgrades. This flaw allows attackers on the path or controlling target hosts to intercept sensitive IBM IAM tokens, AWS S3 Express tokens, and customer-provided server-side encryption keys (SSE-C).
A protocol-level CRLF injection vulnerability exists in rclone's FTP backend before version 1.75.0. When configured with a non-default filename encoding, rclone allows carriage return and line feed characters to pass directly into the underlying FTP client library. Because the library constructs line-oriented control commands without input validation, an attacker-controlled filename can inject arbitrary FTP commands into the session, allowing unauthorized file deletion and modification on the target server.
A protocol downgrade vulnerability in rclone's WebDAV backend allows sensitive credentials, cookies, and authentication headers to be transmitted in cleartext. This occurs when a remote server redirects an HTTPS request to a plaintext HTTP URL on the same host, which the Go HTTP client default behavior permits without checking the protocol transport layer. This report provides a detailed technical analysis of the root cause, exploit mechanics, patch diff, and remediation strategies.
An incomplete sanitization vulnerability exists in rclone's SFTP backend before version 1.75.0 when performing server-side hashing operations on Windows hosts. Due to PowerShell treating Unicode smart quotes as equivalent to ASCII single quotes, malicious file paths can escape command string delimiters and execute arbitrary commands on the remote system.
A critical path traversal and authorization bypass vulnerability exists in the rclone serve restic command when multi-user isolation is enabled using the --private-repos flag. Due to a middleware desynchronization flaw, authenticated users can access, modify, or delete backup repositories belonging to other tenants.