VYPR
Moderate severityNVD Advisory· Published Mar 11, 2026· Updated Mar 12, 2026

Shescape escape() leaves bracket glob expansion active on Bash, BusyBox, and Dash

CVE-2026-32094

Description

Shescape is a simple shell escape library for JavaScript. Prior to 2.1.10, Shescape#escape() does not escape square-bracket glob syntax for Bash, BusyBox sh, and Dash. Applications that interpolate the return value directly into a shell command string can cause an attacker-controlled value like secret[12] to expand into multiple filesystem matches instead of a single literal argument, turning one argument into multiple trusted-pathname matches. This vulnerability is fixed in 2.1.10.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
shescapenpm
< 2.1.102.1.10

Affected products

1

Patches

1
6add105c6f6b

Escape bracket glob expansion for Bash, BusyBox, and Dash (#2410)

https://github.com/ericcornelissen/shescapeEric CornelissenMar 10, 2026via ghsa
6 files changed · +45 43
  • CHANGELOG.md+3 2 modified
    @@ -9,7 +9,7 @@ Versioning].
     
     ## [Unreleased]
     
    -- _No changes yet_
    +- Correct escaping of `[` and `]` for Bash, BusyBox, and Dash. ([#2410])
     
     ## [2.1.9] - 2026-03-06
     
    @@ -47,7 +47,7 @@ Versioning].
     
     ## [2.1.2] - 2025-03-25
     
    -- Correct escaping of `%` escaping for CMD. ([#1916])
    +- Correct escaping of `%` for CMD. ([#1916])
     
     ## [2.1.1] - 2024-05-01
     
    @@ -395,6 +395,7 @@ Versioning].
     [#2383]: https://github.com/ericcornelissen/shescape/pull/2383
     [#2387]: https://github.com/ericcornelissen/shescape/pull/2387
     [#2388]: https://github.com/ericcornelissen/shescape/pull/2388
    +[#2410]: https://github.com/ericcornelissen/shescape/pull/2410
     [552e8ea]: https://github.com/ericcornelissen/shescape/commit/552e8eab56861720b1d4e5474fb65741643358f9
     [keep a changelog]: https://keepachangelog.com/en/1.0.0/
     [semantic versioning]: https://semver.org/spec/v2.0.0.html
    
  • src/internal/unix/bash.js+1 1 modified
    @@ -17,7 +17,7 @@ export function getEscapeFunction() {
       const backslashes = new RegExp("\\\\", "g");
       const comments = new RegExp("(^|\\s)#", "g");
       const home = new RegExp("(^|[\\s:=])~", "g");
    -  const specials = new RegExp("([\"$&'()*;<>?`{|])", "g");
    +  const specials = new RegExp("([\"$&'()*;<>?[\\]`{|])", "g");
       const whitespace = new RegExp("([\t ])", "g");
       return (arg) =>
         arg
    
  • src/internal/unix/busybox.js+1 1 modified
    @@ -17,7 +17,7 @@ export function getEscapeFunction() {
       const backslashes = new RegExp("\\\\", "g");
       const comments = new RegExp("(^|\\s)#", "g");
       const home = new RegExp("(^|\\s)~", "g");
    -  const specials = new RegExp("([\"$&'()*;<>?`|])", "g");
    +  const specials = new RegExp("([\"$&'()*;<>?[\\]`|])", "g");
       const whitespace = new RegExp("([\t ])", "g");
       return (arg) =>
         arg
    
  • src/internal/unix/dash.js+1 1 modified
    @@ -15,7 +15,7 @@ function escapeArg(arg) {
         .replace(/\n/gu, " ")
         .replace(/\\/gu, "\\\\")
         .replace(/(?<=^|\s)([#~])/gu, "\\$1")
    -    .replace(/(["$&'()*;<>?`|])/gu, "\\$1")
    +    .replace(/(["$&'()*;<>?[\]`|])/gu, "\\$1")
         .replace(/([\t ])/gu, "\\$1");
     }
     
    
  • test/fixtures/unix.js+38 38 modified
    @@ -2236,53 +2236,53 @@ export const escape = {
         "square brackets ('[', ']')": [
           {
             input: "a[b",
    -        expected: "a[b",
    +        expected: "a\\[b",
           },
           {
             input: "a[b[c",
    -        expected: "a[b[c",
    +        expected: "a\\[b\\[c",
           },
           {
             input: "a[",
    -        expected: "a[",
    +        expected: "a\\[",
           },
           {
             input: "[a",
    -        expected: "[a",
    +        expected: "\\[a",
           },
           {
             input: "a]b",
    -        expected: "a]b",
    +        expected: "a\\]b",
           },
           {
             input: "a]b]c",
    -        expected: "a]b]c",
    +        expected: "a\\]b\\]c",
           },
           {
             input: "a]",
    -        expected: "a]",
    +        expected: "a\\]",
           },
           {
             input: "]a",
    -        expected: "]a",
    +        expected: "\\]a",
           },
           {
             input: "a[b]c",
    -        expected: "a[b]c",
    +        expected: "a\\[b\\]c",
           },
         ],
         "square brackets ('[', ']') + commas (',')": [
           {
             input: "a[b,c]d",
    -        expected: "a[b,c]d",
    +        expected: "a\\[b,c\\]d",
           },
           {
             input: "a[,b]c",
    -        expected: "a[,b]c",
    +        expected: "a\\[,b\\]c",
           },
           {
             input: "a[b,]c",
    -        expected: "a[b,]c",
    +        expected: "a\\[b,\\]c",
           },
         ],
         "curly brackets ('{', '}')": [
    @@ -3496,53 +3496,53 @@ export const escape = {
         "square brackets ('[', ']')": [
           {
             input: "a[b",
    -        expected: "a[b",
    +        expected: "a\\[b",
           },
           {
             input: "a[b[c",
    -        expected: "a[b[c",
    +        expected: "a\\[b\\[c",
           },
           {
             input: "a[",
    -        expected: "a[",
    +        expected: "a\\[",
           },
           {
             input: "[a",
    -        expected: "[a",
    +        expected: "\\[a",
           },
           {
             input: "a]b",
    -        expected: "a]b",
    +        expected: "a\\]b",
           },
           {
             input: "a]b]c",
    -        expected: "a]b]c",
    +        expected: "a\\]b\\]c",
           },
           {
             input: "a]",
    -        expected: "a]",
    +        expected: "a\\]",
           },
           {
             input: "]a",
    -        expected: "]a",
    +        expected: "\\]a",
           },
           {
             input: "a[b]c",
    -        expected: "a[b]c",
    +        expected: "a\\[b\\]c",
           },
         ],
         "square brackets ('[', ']') + commas (',')": [
           {
             input: "a[b,c]d",
    -        expected: "a[b,c]d",
    +        expected: "a\\[b,c\\]d",
           },
           {
    -        input: "a[,b]c",
    -        expected: "a[,b]c",
    +        input: "a[b,]c",
    +        expected: "a\\[b,\\]c",
           },
           {
    -        input: "a[b,]c",
    -        expected: "a[b,]c",
    +        input: "a[,b]c",
    +        expected: "a\\[,b\\]c",
           },
         ],
         "curly brackets ('{', '}')": [
    @@ -5762,53 +5762,53 @@ export const escape = {
         "square brackets ('[', ']')": [
           {
             input: "a[b",
    -        expected: "a[b",
    +        expected: "a\\[b",
           },
           {
             input: "a[b[c",
    -        expected: "a[b[c",
    +        expected: "a\\[b\\[c",
           },
           {
             input: "a[",
    -        expected: "a[",
    +        expected: "a\\[",
           },
           {
             input: "[a",
    -        expected: "[a",
    +        expected: "\\[a",
           },
           {
             input: "a]b",
    -        expected: "a]b",
    +        expected: "a\\]b",
           },
           {
             input: "a]b]c",
    -        expected: "a]b]c",
    +        expected: "a\\]b\\]c",
           },
           {
             input: "a]",
    -        expected: "a]",
    +        expected: "a\\]",
           },
           {
             input: "]a",
    -        expected: "]a",
    +        expected: "\\]a",
           },
           {
             input: "a[b]c",
    -        expected: "a[b]c",
    +        expected: "a\\[b\\]c",
           },
         ],
         "square brackets ('[', ']') + commas (',')": [
           {
             input: "a[b,c]d",
    -        expected: "a[b,c]d",
    +        expected: "a\\[b,c\\]d",
           },
           {
             input: "a[b,]c",
    -        expected: "a[b,]c",
    +        expected: "a\\[b,\\]c",
           },
           {
             input: "a[,b]c",
    -        expected: "a[,b]c",
    +        expected: "a\\[,b\\]c",
           },
         ],
         "curly brackets ('{', '}')": [
    
  • test/fuzz/corpus/e00161899be97ad52705bea9b53f7428734db7270d26032ea6af0c6b953df045+1 0 added
    @@ -0,0 +1 @@
    +pa[c]kage.json
    \ No newline at end of file
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.