Jul 25, 2026·7 min read·1 visit
Shescape failed to escape critical shell control characters when placed immediately after punctuation, leading to path disclosure in Unix shells and syntax breakout in Windows cmd.exe.
An incomplete escaping vulnerability in the npm package 'shescape' allows unauthenticated users to trigger dynamic shell expansions, absolute path disclosure, and command block break-outs on Unix and Windows systems.
The NPM library shescape is a utility designed to escape command-line arguments to prevent command injection vulnerabilities in Node.js applications. When developers execute shell commands using dynamic arguments, they rely on escaping mechanisms to neutralize special characters that shells interpret as control operators. This vulnerability represents a parser differential where the library's escaping logic fails to align with the parsing behavior of downstream shell interpreters such as Zsh, Dash, and Windows Command Prompt.
In Unix-like systems, character sequences like ~ (tilde expansion), ^ (extended globbing), and # (comments) possess active properties depending on active shell configuration options. Similarly, Windows cmd.exe utilizes parentheses ( and ) for command grouping in control blocks. Prior to the fix, Shescape executed conditional, pattern-based escaping that only neutralized these characters when they appeared at the start of an argument or were immediately preceded by whitespace.
Because of this design flaw, an attacker can input arguments where active shell characters are preceded by other punctuation characters such as = or :. Shescape processes these patterns as safe literals and skips escaping them. However, when the downstream system shell parses the argument, it executes the dynamic expansion or structural evaluation, bypassing the security boundaries established by the library.
The primary root cause of this vulnerability lies in the context-restricted regular expressions used in Shescape's escape functions. For Unix platforms running Zsh and Dash, the package attempted to optimize or restrict escaping of tildes and hashtags to minimize unnecessary backslashes. It implemented regular expressions that required a preceding space or the start of the string to trigger an escape action.
For example, the old Zsh regexes were defined as:
const comments = new RegExp(/(^|\s)#/g);
const expansions = new RegExp(/(^|\s)([=~])/g);These regular expressions fail to match if a tilde or hashtag is preceded by punctuation instead of whitespace. In standard POSIX shells and Dash, tilde expansion is performed not only at the beginning of a word but also immediately following a colon : or an equals sign = (common in environment variable definitions or path lists). Zsh, particularly with the EXTENDED_GLOB option enabled, treats ^ and ~ as active pattern operators regardless of their placement relative to whitespace.
Additionally, the Windows Command Prompt escaping module completely omitted parentheses from its set of special characters. The old regular expression was defined as:
const specials = new RegExp(/([%&<>^|])/g);Because parentheses were not classified as special characters, they passed through the escape module unaltered. This allowed unescaped execution context manipulation within complex shell blocks. Finally, the internal composition logic in src/internal/compose.js parsed multi-segment flags using an array-shifting loop that could fail to align subsequent escape configurations if a segment returned an empty string, creating an auxiliary bypass vector.
The vulnerability was resolved across two release branches: the v3 line (patched in 3.0.1) and the v2 line (backported in 2.1.14). The core fix shifts Shescape from conditional, context-restricted regular expressions to unconditional escaping of unsafe shell control characters.
In src/internal/unix/zsh.js, the conditional tilde and hashtag matchers were removed. The #, ^, and ~ characters were added directly to the unconditional specials character class:
- const comments = new RegExp(/(^|\s)#/g);
- const expansions = new RegExp(/(^|\s)([=~])/g);
- const specials = new RegExp(/(["$&'()*;<>?[\]`{|}])/g);
+ const expansions = new RegExp(/(^|[\s:=])=/g);
+ const specials = new RegExp(/(["#$&'()*;<>?[\]^`{|}~])/g);For src/internal/unix/dash.js, the tilde matching regex was widened to capture assignments and path prefixes starting with : or =. This aligns the escaping boundary with standard POSIX assignment behavior:
- const home = new RegExp(/(^|\s)~/g);
+ const home = new RegExp(/(^|[\s:=])~/g);For Windows environments in src/internal/win/cmd.js, parentheses were integrated into the specials regex to prevent syntax breakouts inside parenthesized command groups:
- const specials = new RegExp(/([%&<>^|])/g);
+ const specials = new RegExp(/([%&()<>^|])/g);In src/internal/compose.js, the array-shifting composition loop was refactored. The fragile array-destructuring loop was replaced with an index-based boundary loop that evaluates the returned values of escape functions reliably:
- let [preFlag, , ...rest] = flagFn(arg);
- while (rest.length > 0 && escapeFn(preFlag) === "") {
- arg = rest.join("");
- [preFlag, , ...rest] = rest;
- }
+ const fragments = flagFn(arg);
+
+ let idx = 0;
+ for (; idx < fragments.length - 2; idx += 2) {
+ const escapedFragment = escapeFn(fragments[idx]);
+ if (escapedFragment !== "") {
+ break;
+ }
+ }
+
+ arg = fragments.slice(idx).join("");Exploitation of this vulnerability requires the target application to pass unsanitized user input through Shescape into a shell execution context. The exact security impact varies based on the target OS, shell, and shell-specific options.
Consider an application that defines an execution wrapper such as:
import { escape } from 'shescape';
import { exec } from 'child_process';
function runCommand(userInput) {
const escapedInput = escape(userInput);
exec(`echo ${escapedInput}`, { shell: '/bin/zsh' }, (err, stdout) => {
console.log(stdout);
});
}An attacker can supply the input test=~ to trigger the vulnerability. When Shescape processes this input, the conditional regex /(^|\s)([=~])/ fails to match because the tilde is preceded by =. The input is returned unescaped as test=~. When the command is passed to /bin/zsh, the shell performs tilde expansion on the assignment structure, converting the tilde into the absolute path of the executing user (e.g., /home/node-app). The command executed becomes echo test=/home/node-app, leaking the internal directory structure in the output.
Under Windows cmd.exe, a similar bypass exists when parameters are executed inside standard control blocks (such as FOR loops or IF statements). By injecting parentheses such as ) & calc.exe & (, an attacker can close the application's native command group, execute arbitrary commands, and open a new group to satisfy syntax requirements, leading to remote command execution.
The primary impact of this vulnerability is information disclosure in the form of absolute path disclosure. By forcing the shell to expand tildes, attackers can map out the backend server's file system structure, identify valid username directories, and confirm the presence of specific files or directories.
If the application operates within Zsh and has EXTENDED_GLOB enabled, an attacker can use the negation operator ^ or other globbing operators to interact with the file system. For example, passing ^exclusion_pattern can trigger directory listings of all files not matching the pattern, resulting in file enumeration.
On Windows systems running cmd.exe, the impact can escalate to remote code execution. Because parenthesized command blocks can be broken out of, an attacker who controls parameters parsed inside IF or FOR statements can inject arbitrary shell commands. This changes the impact from low-severity information disclosure to high-severity integrity and confidentiality compromise.
Remediation of this vulnerability requires upgrading the shescape dependency to the appropriate patched release. The development team has issued patches for both major release lines.
For applications utilizing the 2.x branch, upgrade to version 2.1.14 or later. For applications utilizing the 3.x branch, upgrade to version 3.0.1 or later. These versions contain the updated, context-agnostic regular expressions and the corrected flag composition logic.
If upgrading is not immediately feasible, you can apply temporary mitigation strategies. Validate and sanitize user inputs to reject characters like ~, #, ^, (, and ) before passing them to the escaping library. Alternatively, restructure system execution routines to avoid launching commands via a shell interpreter. Using APIs like child_process.execFile or child_process.spawn with direct argument arrays avoids the shell parser entirely, neutralizing this class of vulnerability.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
shescape ericcornelissen | < 2.1.14 | 2.1.14 |
shescape ericcornelissen | == 3.0.0 | 3.0.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-200 / CWE-20 |
| Attack Vector | Local / Network |
| CVSS v3.1 Score | 6.5 |
| Exploit Status | poc |
| CISA KEV Status | Not Listed |
| Impact | Absolute Path Disclosure / Command Execution Bypass |
The product exposes sensitive information to an actor who is not authorized to have access to that information.
A security policy bypass vulnerability exists in the AWS API MCP Server (awslabs-aws-api-mcp-server) from version 0.2.13 through 1.3.46. When the server fails to load the read-only operations index during startup (due to transient network failures, file permission issues, or other exceptions), it logs a warning but continues running in an insecure, degraded state. Under this condition, the security policy engine fails open, silently skipping all subsequent security checks and consent prompts for the lifetime of the process. This permits unauthorized mutating AWS CLI commands to execute via indirect prompt injection attacks.
A critical command injection vulnerability in the shescape npm library affects Windows systems when running shell commands using cmd.exe. The escaping function fails to neutralize parentheses, allowing attackers to close shell blocks and execute arbitrary commands.
An escaping bypass in the npm package shescape on Unix platforms utilizing the Dash shell can result in unauthorized home directory path disclosure. The vulnerability occurs when user input containing specific sequences is passed inside shell variable assignment contexts. Additionally, the patch addresses secondary security gaps related to Zsh extended globbing and Windows CMD command block breakouts.
A high-severity algorithmic-complexity vulnerability in the Node.js library Shescape leads to a Quadratic-Time Denial of Service (DoS) when flag protection is enabled. By supplying inputs containing repetitive control characters and hyphens, remote attackers can trigger an inefficient nested loop in Shescape's argument-composition logic, blocking the Node.js single-threaded event loop and causing total application Denial of Service.
A multi-vector vulnerability advisory in the OmniFaces JavaServer Faces (JSF) utility library covers flaws leading to unauthenticated arbitrary file access, memory exhaustion (DoS), cross-site scripting (XSS), and WebSocket push channel hijacking.
Oh My Posh prior to version 29.35.1 is vulnerable to terminal escape sequence injection. Dynamic strings from directory names or Git repository metadata are written to the prompt output without neutralization, enabling unauthenticated remote code execution, clipboard hijacking, or terminal DoS when users navigate to malicious folders.