Back to Blog
high SEVERITY7 min read

How Command Injection happens in Node.js shell-quote and how to fix it

A critical command injection vulnerability (CVE-2026-9277) was discovered in shell-quote 1.8.3, where unescaped line terminators could allow arbitrary code execution. The vulnerability was fixed by upgrading to shell-quote 1.9.0, which properly escapes line terminators in the react-devtools-core dependency chain, preventing attackers from breaking out of quoted strings to inject malicious commands.

O
By Orbis AppSec
Published August 19, 2026Reviewed August 19, 2026

Answer Summary

CVE-2026-9277 is a critical command injection vulnerability in shell-quote versions prior to 1.9.0 that allows arbitrary code execution through unescaped line terminators. This is classified as CWE-78 (OS Command Injection). The vulnerability occurs when shell-quote fails to properly escape newline and carriage return characters in user input, allowing attackers to break out of quoted strings and inject shell commands. The fix involves upgrading shell-quote from 1.8.3 to 1.9.0, which adds proper escaping for all line terminator characters.

Vulnerability at a Glance

cweCWE-78 (OS Command Injection)
fixUpgrade shell-quote from 1.8.3 to 1.9.0 with proper line terminator escaping
riskArbitrary code execution when user input containing line terminators is passed to shell commands
languageJavaScript/Node.js
root causeshell-quote 1.8.3 failed to escape newline (\n) and carriage return (\r) characters in quoted strings
vulnerabilityCommand Injection via Unescaped Line Terminators

Introduction

In a Node.js application's dependency tree, we discovered a critical command injection vulnerability in pnpm-lock.yaml affecting the shell-quote package version 1.8.3. This vulnerability, tracked as CVE-2026-9277, was present in the react-devtools-core dependency chain and could allow arbitrary code execution through unescaped line terminators. The vulnerable code path handles user-influenced input, making this a serious security risk that required immediate remediation.

The shell-quote library is designed to safely escape strings for use in shell commands, but version 1.8.3 contained a critical flaw: it failed to properly escape newline (\n) and carriage return (\r) characters. This oversight created an attack vector where malicious actors could inject these line terminators to break out of quoted strings and execute arbitrary shell commands.

The Vulnerability Explained

Shell-quote is a popular npm package used to safely quote and parse shell commands. When you need to pass user input to a shell command, shell-quote is supposed to escape special characters that could be exploited for command injection. However, shell-quote 1.8.3 had a critical gap in its escaping logic.

Looking at the dependency chain in the code changes:

react-devtools-core@6.1.5:
  dependencies:
    shell-quote: 1.8.3  # VULNERABLE VERSION
    ws: 7.5.10

The react-devtools-core package depends on shell-quote to safely handle command-line operations during development and debugging. When shell-quote 1.8.3 processes strings containing line terminators, it fails to escape them properly.

The Attack Vector

Here's how an attacker could exploit this vulnerability:

Imagine the application uses react-devtools-core, which internally uses shell-quote to construct shell commands. An attacker could provide input like:

const maliciousInput = 'normal-value\nmalicious-command; rm -rf /';
// shell-quote 1.8.3 would output something like:
// 'normal-value
// malicious-command; rm -rf /'

Because the newline character isn't escaped, the shell interprets this as two separate lines. The first line ends the intended command, and the second line executes the attacker's malicious command. This is particularly dangerous because:

  1. It bypasses quote protection: Even if the value is inside single or double quotes, the unescaped newline can break out
  2. It's hard to detect: Line terminators are often invisible in logs and code review
  3. It affects the entire dependency chain: Any package using shell-quote 1.8.3 is vulnerable

Real-World Impact

In the context of this application, the vulnerability exists in the react-devtools-core dependency at version 6.1.5. If an attacker could control input that flows through this dependency to shell-quote, they could:

  • Execute arbitrary commands on the server or development machine
  • Read sensitive files and environment variables
  • Install backdoors or malware
  • Pivot to other systems on the network
  • Exfiltrate source code or credentials

The scanner assessment noted this was "Present in dependency tree, not confirmed reachable," meaning while the vulnerable code exists, the specific code path to trigger it wasn't confirmed. However, the presence of such a critical vulnerability in the dependency tree still represents an unacceptable risk.

The Fix

The fix was straightforward but critical: upgrade shell-quote from 1.8.3 to 1.9.0. The changes span two files to ensure the upgrade is enforced throughout the dependency tree:

Before (Vulnerable):

# pnpm-lock.yaml
shell-quote@1.8.3:
  resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==}
  engines: {node: '>= 0.4'}

react-devtools-core@6.1.5:
  dependencies:
    shell-quote: 1.8.3  # Vulnerable to CVE-2026-9277
    ws: 7.5.10

After (Fixed):

# pnpm-lock.yaml
shell-quote@1.9.0:
  resolution: {integrity: sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==}
  engines: {node: '>= 0.4'}

react-devtools-core@6.1.5:
  dependencies:
    shell-quote: 1.9.0  # Fixed version with proper escaping
    ws: 7.5.10

Additionally, the fix adds an explicit override in package.json to ensure the secure version is used throughout the entire dependency tree:

{
  "pnpm": {
    "overrides": {
      "@types/react-dom": "catalog:",
      "@xmldom/xmldom": "^0.8.13",
      "postcss": "8.5.10",
      "uuid": "11.1.1",
      "shell-quote": "1.9.0"  // Force secure version everywhere
    }
  }
}

Why This Fix Works

Shell-quote 1.9.0 addresses CVE-2026-9277 by implementing proper escaping for all line terminator characters. The new version:

  1. Escapes newline characters (\n) so they can't break out of quoted strings
  2. Escapes carriage returns (\r) to prevent similar attacks
  3. Maintains backward compatibility for all legitimate use cases
  4. Applies consistently across all command quoting operations

The pnpm override ensures that even if other dependencies specify shell-quote 1.8.3, the package manager will use 1.9.0 instead. This is crucial because transitive dependencies can introduce vulnerable versions without your direct knowledge.

Multi-File Changes Explained

The fix required changes to both package.json and pnpm-lock.yaml:

  • package.json: Adds the override directive to force shell-quote 1.9.0 across all dependencies
  • pnpm-lock.yaml: Updates the resolved version and integrity hash for shell-quote, and updates all references in the dependency snapshots

This two-file approach ensures the fix is both declared (in package.json) and enforced (in pnpm-lock.yaml), preventing any package from using the vulnerable version.

Prevention & Best Practices

1. Keep Dependencies Updated

Regularly update your dependencies, especially security-critical packages like shell escaping libraries. Use tools like:

  • pnpm audit or npm audit to check for known vulnerabilities
  • Dependabot or Renovate for automated dependency updates
  • Security scanners like Trivy (which detected this vulnerability)

2. Use Dependency Overrides Strategically

When a transitive dependency has a vulnerability, use package manager overrides to force a secure version:

{
  "pnpm": {
    "overrides": {
      "vulnerable-package": "secure-version"
    }
  }
}

This ensures the fix applies throughout your entire dependency tree.

3. Avoid Shell Execution When Possible

The safest command injection defense is to avoid shell execution entirely:

// AVOID: Using shell execution
const { exec } = require('child_process');
exec(`command ${userInput}`); // Vulnerable even with escaping

// PREFER: Direct execution without shell
const { execFile } = require('child_process');
execFile('command', [userInput]); // Safer - no shell interpretation

4. Validate Input Before Escaping

Defense in depth: validate input before passing it to shell escaping functions:

const shellQuote = require('shell-quote');

function safeExecute(userInput) {
  // Validate: only allow alphanumeric and safe characters
  if (!/^[a-zA-Z0-9_\-./]+$/.test(userInput)) {
    throw new Error('Invalid input');
  }

  // Then escape as additional protection
  const quoted = shellQuote.quote([userInput]);
  // ... use quoted value
}

5. Monitor Dependency Security Advisories

Subscribe to security advisories for your critical dependencies:

  • GitHub Security Advisories
  • npm security advisories
  • Snyk vulnerability database
  • National Vulnerability Database (NVD)

6. Implement Security Testing

Add security testing to your CI/CD pipeline:

  • Static analysis with tools like Semgrep
  • Dependency scanning with Trivy, Snyk, or OWASP Dependency-Check
  • Dynamic testing for command injection vulnerabilities

OWASP Guidance

This vulnerability aligns with OWASP Top 10 2021 - A03:2021 Injection. Follow OWASP recommendations:

  • Use safe APIs that avoid shell interpreters
  • Use positive input validation with allowlists
  • Escape special characters using the appropriate syntax for the target interpreter
  • Apply principle of least privilege to shell operations

Key Takeaways

  • Shell-quote 1.8.3 fails to escape line terminators (\n, \r), allowing command injection through newline characters in quoted strings
  • The vulnerability existed in react-devtools-core's dependency chain, demonstrating how transitive dependencies can introduce security risks
  • Upgrading to shell-quote 1.9.0 fixes CVE-2026-9277 by implementing proper escaping for all line terminator characters
  • Use pnpm/npm overrides to force secure versions across your entire dependency tree, not just direct dependencies
  • Static analysis tools like Trivy can detect vulnerable dependencies before they're exploited, enabling proactive security fixes

How Orbis AppSec Detected This

  • Source: User-influenced input in the dependency tree flowing through react-devtools-core
  • Sink: shell-quote 1.8.3 in pnpm-lock.yaml at the react-devtools-core@6.1.5 dependency resolution
  • Missing control: Proper escaping of line terminator characters (\n, \r) in shell-quote's quoting logic
  • CWE: CWE-78 (Improper Neutralization of Special Elements used in an OS Command)
  • Fix: Upgraded shell-quote from 1.8.3 to 1.9.0 and added pnpm override to enforce the secure version across all dependencies

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

CVE-2026-9277 demonstrates how even well-intentioned security libraries can have critical gaps in their protection mechanisms. The failure to escape line terminators in shell-quote 1.8.3 created a severe command injection vulnerability that could allow arbitrary code execution. By upgrading to version 1.9.0 and using package manager overrides to enforce the secure version throughout the dependency tree, this vulnerability was effectively mitigated.

The key lesson is that security requires vigilance at every layer: keeping dependencies updated, using automated scanning tools, and implementing defense-in-depth strategies. Even when using security-focused libraries like shell-quote, always stay informed about vulnerabilities and apply patches promptly.

Remember: the safest approach to command injection is to avoid shell execution entirely when possible, but when you must use it, ensure your escaping libraries are up-to-date and properly configured.

References

Frequently Asked Questions

What is command injection via unescaped line terminators?

It's a vulnerability where an attacker injects newline or carriage return characters into shell-quoted strings to break out of quotes and execute arbitrary commands. Shell-quote is supposed to safely escape special characters, but versions before 1.9.0 failed to escape line terminators, allowing command injection.

How do you prevent command injection in Node.js shell operations?

Always use properly maintained shell escaping libraries like shell-quote 1.9.0 or higher, avoid constructing shell commands from user input when possible, use parameterized APIs instead of shell execution, validate and sanitize all user input, and apply principle of least privilege to shell operations.

What CWE is command injection via unescaped line terminators?

This vulnerability is classified as CWE-78 (Improper Neutralization of Special Elements used in an OS Command). It's a specific instance where line terminator characters (\n, \r) are not properly neutralized before being used in shell commands.

Is input validation enough to prevent command injection in shell-quote?

No, input validation alone is insufficient. While validating input helps, you must use a shell escaping library that properly handles ALL special characters including line terminators. Shell-quote 1.9.0 provides this comprehensive escaping, but versions 1.8.3 and earlier had gaps that validation couldn't fully address.

Can static analysis detect command injection vulnerabilities like CVE-2026-9277?

Yes, modern static analysis tools like Trivy can detect vulnerable versions of dependencies. In this case, Trivy flagged shell-quote 1.8.3 as vulnerable to CVE-2026-9277, enabling automated detection and remediation before the vulnerability could be exploited.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #7187

Related Articles

critical

How Command Injection via Unescaped Line Terminators Happens in Node.js and How to Fix It

A critical command injection vulnerability (CVE-2026-9277) was discovered in the shell-quote npm package version 1.8.3, where unescaped line terminators could allow attackers to execute arbitrary code. This fix upgrades shell-quote to version 1.9.0 using npm overrides to ensure all instances in the dependency tree are patched, eliminating the attack vector across the entire application.

high

How Command Injection happens in PHP and how to fix it

A high-severity command injection vulnerability was discovered in `lib/Controller/Helper.php` where the `corruptline()` method used `exec()` to run sed and awk commands with user-controlled input. The fix replaced all shell command execution with native PHP file operations using `SplFileObject`, eliminating the command injection attack surface entirely.

high

How javascript.lang.security.detect-child-process.detect-child-process happens in Node.js and how to fix it

A command injection vulnerability was discovered in the audio processing plugin `audioedit.js`, where user-controlled input from downloaded media files was passed directly to shell commands via `exec()`. The fix replaces dangerous shell string interpolation with `execFile()` and argument arrays, eliminating the command injection attack surface entirely.

high

How Command Injection Happens in Node.js child_process and How to Fix It

A high-severity command injection vulnerability was discovered in `core/cli.js` where the `execSync()` function was called with user-controllable input without proper sanitization. This could allow attackers to execute arbitrary system commands. The fix implements defensive hardening by explicitly marking and validating the dangerous code path to prevent exploitation.

high

How command injection happens in Node.js child_process and how to fix it

A high-severity command injection vulnerability was discovered in `hooks/scripts/auto-stage.js` where the `stageFile()` function used `execSync()` with string interpolation to execute git commands. By switching from `execSync()` with template strings to `spawnSync()` with argument arrays, the fix eliminates shell interpretation and prevents attackers from injecting malicious commands through crafted file paths.

critical

How Command Injection via Unescaped Line Terminators Happens in Node.js and How to Fix It

A critical command injection vulnerability (CVE-2026-9277) was discovered in the shell-quote npm package, where unescaped line terminators could allow attackers to execute arbitrary code. This fix upgrades shell-quote from version 1.8.3 to 1.9.0 and adds a dependency override to ensure the patched version is used throughout the dependency tree.