CVE-2026-9277: shell-quote `quote()` does not validate object-token shapes, allowing command injection via line terminators in `.op`

Published May 22, 2026
·
Updated

Summary

shell-quote's quote() function did not validate object-token inputs against the operator model used by parse(). The .op field was backslash-escaped character by character using /(.)/g, which in JavaScript does not match line terminators (\n, \r, U+2028, U+2029). A line terminator in .op therefore passed through unescaped into the output; POSIX shells treat a literal \n as a command separator, so any content after it would execute as a second command.

The vulnerable code path is reachable in two ways. Neither requires the parser to misbehave — parse() only emits ops from a fixed control set — but both are documented API surface:

1. Direct construction. A caller builds { op: '...\n...' } from external input (e.g. a deserialized argument array) and passes it to quote(). 2. envFn return. parse(cmd, envFn) is documented to splice the return value of envFn into the result array when it is an object. An attacker-influenced data source consulted by envFn can introduce an object token whose .op reaches quote().

Impact

Shell command injection in callers that pass object tokens with attacker-influenced .op values to quote() and then hand the result to a shell. The preconditions are narrower than ordinary string injection — they require the caller to feed object tokens into quote() — but object tokens are a public, documented part of the API surface, and quote() is intended to be a shell-safety boundary.

PoC

js const { parse, quote } = require('shell-quote');

// Direct construction quote([{ op: ';\nid' }]); // → "\;\n\\i\\d" ← literal newline; second line executes as a command

// Via parse() with an envFn returning attacker-shaped objects const tokens = parse('echo $X', () => ({ op: ';\nid' })); require('childprocess').execSync(quote(tokens), { shell: true }); // Executes id after echo \;.

Confirmed under sh, bash, dash, and zsh.

Patch

Fixed by replacing the per-character escape with strict shape validation in quote(). The object-token branch now:

- { op } — .op must be a string from the same allowlist the parser emits (||, &&, ;;, |&, <(, <<<, >>, >&, <&, &, ;, (, ), |, <, >). Anything else throws TypeError. This is the direct fix for the reported issue and removes the entire class of .op injection. - { op: 'glob', pattern } — .pattern must be a string with no line terminators. Glob metacharacters (, ?, [, ], {, }, ,) pass through; all other shell-special characters are backslash-escaped. (Previously the pattern field was discarded entirely and the literal string \g\l\o\b was emitted — a latent bug, not security-relevant.) - { comment } — .comment must be a string with no line terminators (line terminators would end the shell comment and resume command parsing — same injection shape). - Any other object shape — TypeError.

The fix is allowlist-based rather than a targeted regex tweak, so it closes the reported vector and forecloses adjacent ones (U+2028 / U+2029 line separators in .op, line terminators in comments, unknown-shape objects coerced through .replace).

Workarounds

Prior to upgrading, callers that build object tokens from untrusted input should validate .op against the parser's operator set themselves, and never construct { op } from attacker-controlled strings.

Credits

Reported by Akshat Sinha

Other sources

shell-quote's quote() function did not validate object-token inputs against the operator model used by parse(). The .op field was backslash-escaped character by character using /(.)/g, which in JavaScript does not match line terminators (\n, \r, U+2028, U+2029). A line terminator in .op therefore passed through unescaped into the output; POSIX shells treat a literal newline as a command separator, so any content after it would execute as a second command. The vulnerable code path is reachable in two ways: (1) direct construction of { op: '...\n...' } from external input, and (2) via parse(cmd, envFn) when envFn returns object tokens whose .op is attacker-influenced. Both are documented API surface. Fixed by replacing the per-character escape with strict shape validation: .op must match the parser's control-operator allowlist; { op: 'glob', pattern } validates pattern and forbids line terminators; { comment } validates comment and forbids line terminators; any other object shape throws TypeError.

MITRE

Affected Software

3 affected componentsFixes available
npm/shell-quote<1.8.4
debian/node-shell-quote<=1.7.4+~1.7.1-1
1.7.4+~1.7.1-1+deb12u11.7.4+~1.7.1-1+deb13u11.8.4+~1.7.5-1
npm/shell-quote>=1.1.0<=1.8.3
1.8.4

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade debian/node-shell-quote to a version that resolves this vulnerability.

    Fixed in 1.7.4+~1.7.1-1+deb12u1Fixed in 1.7.4+~1.7.1-1+deb13u1Fixed in 1.8.4+~1.7.5-1
  2. Upgrade

    Upgrade npm/shell-quote to a version that resolves this vulnerability.

    Fixed in 1.8.4
  3. Upgrade

    Upgrade shell-quote to a version that resolves this vulnerability.

    Fixed in befo1.8.4Patch CVE-2026-9277
  4. Configuration

    In shell-quote's quote(), replace the per-character escape with strict shape validation: require `.op` to match the parser's control-operator allowlist (`||`, `&&`, `;;`, `|&`, `<(`, `<<<`, `>>`, `>&`, `<&`, `&`, `;`, `(`, `)`, `|`, `<`, `>`), require `{ comment }` to be a string with no line terminators, and require `{ op: 'glob', pattern }` to be a string with no line terminators; any other object shape must throw TypeError.

    shell-quote (quote) object-token validation (op/comment/pattern) = allowlist-based shape validation; forbid line terminators
  5. Configuration

    Before calling shell-quote's quote() with object tokens, validate `.op` against the parser's operator set yourself and never construct `{ op }` from attacker-controlled strings.

    Application callers using shell-quote (quote) object-token construction source trust = validated allowlist; never construct `{ op }` from attacker-controlled strings

Event History

May 22, 2026
CVE Published
via MITRE·01:22 PM
Data Sourced
via MITRE·01:22 PM
DescriptionSeverityWeakness
Data Sourced
via Red Hat·02:01 PM
DescriptionSeverityAffected Software
Data Sourced
via NVD·02:16 PM
DescriptionSeverityWeakness
Jun 9, 2026
Data Sourced
via Ubuntu·11:05 AM
RemedyDescriptionSeverityAffected Software
Data Sourced
via Debian·11:06 AM
DescriptionAffected Software
Data Sourced
via Launchpad·11:06 AM
Description
Advisory Published
via GitHub·02:27 PM
Data Sourced
via GitHub·02:27 PM
DescriptionSeverityWeaknessAffected Software
Apr 28, 58520
Event
via FIRST·04:27 AM

Frequently Asked Questions

1

What is the severity of CVE-2026-9277?

CVE-2026-9277 has a severity score of 8.1, categorized as high.

2

What type of vulnerability is CVE-2026-9277?

CVE-2026-9277 is classified as an OS Command Injection vulnerability.

3

How can I mitigate CVE-2026-9277?

To mitigate CVE-2026-9277, ensure that the `quote()` function validates object-token inputs against expected shapes.

4

What is the risk associated with CVE-2026-9277?

The risk level for CVE-2026-9277 is rated at 75, indicating a significant security concern.

5

What is the impact of exploiting CVE-2026-9277?

Exploiting CVE-2026-9277 can allow an attacker to achieve command injection through unfiltered input in the `.op` field.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203