Repository navigation
[SECURITY] Update dependency shell-quote to v1.11.0 - #329
Open
specmatic-builder wants to merge 1 commit into
Open
specmatic-builder wants to merge 1 commit into
specmatic-builder wants to merge 1 commit into
Conversation
specmatic-builder
force-pushed
the
renovate/npm-shell-quote-vulnerability
branch
2 times, most recently
from
August 1, 2026 00:40
a234c12 to
93d876e
Compare
specmatic-builder
force-pushed
the
renovate/npm-shell-quote-vulnerability
branch
2 times, most recently
from
August 15, 2026 00:17
17cd774 to
34cbaa4
Compare
specmatic-builder
force-pushed
the
renovate/npm-shell-quote-vulnerability
branch
from
August 23, 2026 00:17
34cbaa4 to
10e60ea
Compare
specmatic-builder
force-pushed
the
renovate/npm-shell-quote-vulnerability
branch
from
September 4, 2026 00:33
10e60ea to
6b97523
Compare
specmatic-builder
force-pushed
the
renovate/npm-shell-quote-vulnerability
branch
from
September 18, 2026 00:34
6b97523 to
6261620
Compare
specmatic-builder
force-pushed
the
renovate/npm-shell-quote-vulnerability
branch
3 times, most recently
from
October 6, 2026 00:38
fb50599 to
e1ab356
Compare
specmatic-builder
force-pushed
the
renovate/npm-shell-quote-vulnerability
branch
from
October 7, 2026 00:38
e1ab356 to
d145970
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
1.8.4→1.11.0shell-quote: Quadratic-complexity Denial of Service in
parse()(CWE-407)CVE-2026-13311 / GHSA-395f-4hp3-45gv
More information
Details
Summary
shell-quote'sparse()finalizes its token list with areducethat usesArray.prototype.concatas the accumulator. Eachprev.concat(arg)copies the entire growingarray, so
parse()runs in O(n²) in the number of tokens. An unauthenticated attacker whocan submit a string to any code path that calls
parse()on it can block the single-threadedNode.js event loop for tens of seconds with a small input — a denial of service. The trigger
needs no shell metacharacters (plain space-separated words suffice), so input filters that
only screen for
;,|,$, or backticks do not help.Root cause
parse.js(lines 200–203), inparseInternal— this path runs on everyparse()call:prev.concat(arg)allocates a new array and copies all ofprevon every iteration, soproducing an N-token result costs
1 + 2 + … + N = O(N²)copies. A secondacc.concat(s)reduce in the
module.exportswrapper (lines 211–224, reached only whenenvis a function)has the same shape. The maintainer's own
// TODO: replace this whole reduce with a concatalready flags the construct.
Proof of Concept
Measured on
shell-quote@1.8.4, Node v24:parse()Time grows ~×4 per 2× input → confirmed O(n²). A ~128 KB input blocks the event loop ~15 s;

~256 KB → ~57 s; a few hundred KB more → minutes.
poc.js
Impact
parse()is synchronous on the main thread; while it copies arrays quadratically the entireevent loop is blocked and the process serves no other requests. Any service that calls
parse()on attacker-influenced input (command parsers, chat-ops / bot command handlers, REPLs,
build-script / arg-string splitters) can be driven to a sustained DoS with a single small
request. No code execution and no data disclosure — availability only.
End-to-end confirmation: a minimal HTTP server that calls
parse()on the request body, hitwith one
POSTof'x '.repeat(32000)(~63 KB), froze for ~4.5 s. An out-of-process probeclient issuing harmless
GET /pingrequests (normally ~1 ms) observed 27 consecutive pingsstalled by up to 4374 ms during that single request — i.e. every concurrent client was denied
service for the whole parse. Scaling the body to a few hundred KB extends the outage to minutes.
This is the same class as several accepted 2026 advisories for quadratic-parser DoS on
untrusted input (e.g. markdown-it CVE-2026-48988, js-yaml CVE-2026-53550,
python-multipart CVE-2026-53539). It is distinct from the known
shell-quotecommand-injection issues (CVE-2021-42740, CVE-2016-10541, CVE-2026-9277), which are all in
quote(), notparse().Suggested remediation
Replace the O(n²) concat-in-reduce with a linear flatten that pushes into the
accumulator instead of reallocating and copying it on every iteration. Apply the
same shape to the wrapper's
acc.concat(s)reduce. A defensive input-length cap onparse()is a cheap additional stop-gap.Disclosure
Found by source audit + wall-clock confirmation against 1.8.4 (and verified the same code is
present on
main). Reported privately here; no public disclosure until a fix is available.Severity
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
shell-quote: Quadratic-complexity Denial of Service in
parse()(CWE-407)CVE-2026-13311 / GHSA-395f-4hp3-45gv
More information
Details
Summary
shell-quote'sparse()finalizes its token list with areducethat usesArray.prototype.concatas the accumulator. Eachprev.concat(arg)copies the entire growingarray, so
parse()runs in O(n²) in the number of tokens. An unauthenticated attacker whocan submit a string to any code path that calls
parse()on it can block the single-threadedNode.js event loop for tens of seconds with a small input — a denial of service. The trigger
needs no shell metacharacters (plain space-separated words suffice), so input filters that
only screen for
;,|,$, or backticks do not help.Root cause
parse.js(lines 200–203), inparseInternal— this path runs on everyparse()call:prev.concat(arg)allocates a new array and copies all ofprevon every iteration, soproducing an N-token result costs
1 + 2 + … + N = O(N²)copies. A secondacc.concat(s)reduce in the
module.exportswrapper (lines 211–224, reached only whenenvis a function)has the same shape. The maintainer's own
// TODO: replace this whole reduce with a concatalready flags the construct.
Proof of Concept
Measured on
shell-quote@1.8.4, Node v24:parse()Time grows ~×4 per 2× input → confirmed O(n²). A ~128 KB input blocks the event loop ~15 s;

~256 KB → ~57 s; a few hundred KB more → minutes.
poc.js
Impact
parse()is synchronous on the main thread; while it copies arrays quadratically the entireevent loop is blocked and the process serves no other requests. Any service that calls
parse()on attacker-influenced input (command parsers, chat-ops / bot command handlers, REPLs,
build-script / arg-string splitters) can be driven to a sustained DoS with a single small
request. No code execution and no data disclosure — availability only.
End-to-end confirmation: a minimal HTTP server that calls
parse()on the request body, hitwith one
POSTof'x '.repeat(32000)(~63 KB), froze for ~4.5 s. An out-of-process probeclient issuing harmless
GET /pingrequests (normally ~1 ms) observed 27 consecutive pingsstalled by up to 4374 ms during that single request — i.e. every concurrent client was denied
service for the whole parse. Scaling the body to a few hundred KB extends the outage to minutes.
This is the same class as several accepted 2026 advisories for quadratic-parser DoS on
untrusted input (e.g. markdown-it CVE-2026-48988, js-yaml CVE-2026-53550,
python-multipart CVE-2026-53539). It is distinct from the known
shell-quotecommand-injection issues (CVE-2021-42740, CVE-2016-10541, CVE-2026-9277), which are all in
quote(), notparse().Suggested remediation
Replace the O(n²) concat-in-reduce with a linear flatten that pushes into the
accumulator instead of reallocating and copying it on every iteration. Apply the
same shape to the wrapper's
acc.concat(s)reduce. A defensive input-length cap onparse()is a cheap additional stop-gap.Disclosure
Found by source audit + wall-clock confirmation against 1.8.4 (and verified the same code is
present on
main). Reported privately here; no public disclosure until a fix is available.Severity
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
shell-quote:
quote()command injection via a line terminator in a token after a{ comment }tokenCVE-2026-102422 / GHSA-pqg4-j6r4-53mv
More information
Details
Impact
quote()emits a{ comment }token as#followed by its text, which comments out the rest of the shell line, including the opening quote of any later string token. A line terminator in that later string ends the comment, and the rest of the string is parsed as shell input:Passed to
sh,bash,dash,ksh, orzsh, this runsid.parse()emits a comment token for a#in the middle of a word (for examplehttp://example.com/#frag), so callers that combineparse()output with another untrusted string, such asquote(parse(untrustedCommand).concat(untrustedArg)), are affected. The fix for CVE-2026-9277 rejected line terminators in the comment's own text, but not in the tokens after it.Exploitation requires an attacker-controlled string containing a line terminator that follows a
{ comment }token in the samequote()call.Patches
Fixed in v1.11.0:
quote()throws aTypeErrorwhen a string after a{ comment }token contains a line terminator (\n,\r, U+2028, or U+2029).Workarounds
Drop every token after a
{ comment }token before callingquote(), or reject line terminators in untrusted strings. Separately, do not append other shell text afterquote()output that contains a comment, since the comment swallows it.Severity
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Release Notes
ljharb/shell-quote (shell-quote)
v1.11.0Compare Source
Fixed
quote: drop a replace that can never match in the single-quote branch#15parse: support bash ANSI-C quoting ($'...')#32Commits
quote: reject line terminators in tokens after acomment6002b2eparse: preserve text after special shell parameters81b08a5parse: an escaped backslash does not escape the character after itd708019quote: preserve!in arguments that also contain'ad39927parse: treat$_nameas a variable name, not$_followed by text28f88cdquote: preserve empty glob patterns35c9b97quote: escape~in glob patterns to prevent shell tilde-expansion239d49c@ljharb/eslint-config,auto-changelog,eslint,evalmdb1e406eebfc3083429b0dcache-mode36f2394eslint6de9a41v1.10.0Compare Source
Merged
parse: add opt-insplitUnquotedoption for shell field-splitting of unquoted expansions#1Commits
parse: match nested${...}braces so nested parameter expansion is consumed as one substitutionc0842c8parse: pin single-quote literalness and unmatched-quote handlinga0d03e32116fa3quote: pin conservative escaping of=,@,^,,,:,!(#11)1c36f3fquoteoutputs POSIX quoting, notcmd.exe/PowerShell100e96eparse's supported parameter-expansion subsete1c75cdparse: a backslash inside single quotes must not escape the closing quote5d460a32de86f5quote: pin that a backslash with whitespace is not doubled in single quotes (#14)190e236quote: use output verbatim; do not re-quote it (#11)1b36468parse: fix swappedSINGLE_QUOTE/DOUBLE_QUOTEvariable names801af5c59bbf8b@arethetypeswrong/cli,evalmda04d475@arethetypeswrong/ci,eslintd390f9aquote: the tilde test escapes every~, not just a leading one (#9)617d119v1.9.0Compare Source
Commits
dca6e21eslint9aa9e8fparse: finalize tokens in linear time (GHSA-395f-4hp3-45gv)7ff548875e8497@types/esrecurse3fb739dnpm installon Windows to survive npm 2/3 staging-rename flakeabe0163b4bafa2quote: escape leading~to prevent shell tilde-expansion7a76c1aauto-changelog,tape7184b44jackspeakis no longer in the graph9ba368aConfiguration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR has been generated by Renovate Bot. Specmatic specific configuration is managed here.