VYPR
High severityNVD Advisory· Published Aug 1, 2022· Updated Apr 22, 2025

Insufficient escaping of line feeds for CMD in shescape

CVE-2022-31179

Description

Shescape is a simple shell escape package for JavaScript. Versions prior to 1.5.8 were found to be subject to code injection on windows. This impacts users that use Shescape (any API function) to escape arguments for cmd.exe on Windows An attacker can omit all arguments following their input by including a line feed character ('\n') in the payload. This bug has been patched in [v1.5.8] which you can upgrade to now. No further changes are required. Alternatively, line feed characters ('\n') can be stripped out manually or the user input can be made the last argument (this only limits the impact).

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
shescapenpm
< 1.5.81.5.8

Affected products

1

Patches

1
aceea7358f72

Improve testing and escaping of newlines (#332)

https://github.com/ericcornelissen/shescapeEric CornelissenJul 15, 2022via ghsa
15 files changed · +1101 27
  • CHANGELOG.md+7 1 modified
    @@ -7,7 +7,12 @@ Versioning].
     
     ## [Unreleased]
     
    -- _No changes yet_
    +- Fix escaping of line feed characters for Bash, Dash, and Zsh on Unix
    +  systems. ([#332])
    +- Fix escaping of line feed and carriage return characters for PowerShell and
    +  CMD on Windows systems. ([#332])
    +- Fix escaping of `~` and `{` for Bash on Unix systems with input strings
    +  containing line terminating characters. ([#332])
     
     ## [1.5.7] - 2022-07-06
     
    @@ -151,5 +156,6 @@ Versioning].
     [#310]: https://github.com/ericcornelissen/shescape/pull/310
     [#322]: https://github.com/ericcornelissen/shescape/pull/322
     [#324]: https://github.com/ericcornelissen/shescape/pull/324
    +[#332]: https://github.com/ericcornelissen/shescape/pull/332
     [keep a changelog]: https://keepachangelog.com/en/1.0.0/
     [semantic versioning]: https://semver.org/spec/v2.0.0.html
    
  • src/unix.js+6 3 modified
    @@ -46,13 +46,14 @@ function escapeArgBash(arg, interpolation, quoted) {
       if (interpolation) {
         result = result
           .replace(/\\/g, "\\\\")
    +      .replace(/\n/g, " ")
           .replace(/(^|\s)(~|#)/g, "$1\\$2")
           .replace(/(\*|\?)/g, "\\$1")
           .replace(/(\$|\;|\&|\|)/g, "\\$1")
           .replace(/(\(|\)|\<|\>)/g, "\\$1")
           .replace(/("|'|`)/g, "\\$1")
    -      .replace(/\{(?=(.*?(?:\,|\.).*?)\})/g, "\\{")
    -      .replace(/(?<=\=(?:.*?:)?)(~)(?=\:|\=|\-|\+|\/|0|\s|$)/g, "\\$1");
    +      .replace(/\{(?=([^]*?(?:\,|\.)[^]*?)\})/g, "\\{")
    +      .replace(/(?<=\=(?:[^]*?:)?)(~)(?=\:|\=|\-|\+|\/|0|\s|$)/g, "\\$1");
       } else if (quoted) {
         result = result.replace(/'/g, `'\\''`);
       }
    @@ -74,12 +75,13 @@ function escapeArgDash(arg, interpolation, quoted) {
       if (interpolation) {
         result = result
           .replace(/\\/g, "\\\\")
    +      .replace(/\n/g, " ")
           .replace(/(^|\s)(~|#)/g, "$1\\$2")
           .replace(/(\*|\?)/g, "\\$1")
           .replace(/(\$|\;|\&|\|)/g, "\\$1")
           .replace(/(\(|\)|\<|\>)/g, "\\$1")
           .replace(/("|'|`)/g, "\\$1")
    -      .replace(/\{(?=(.*?(?:\,|\.).*?)\})/g, "\\{");
    +      .replace(/\{(?=([^]*?(?:\,|\.)[^]*?)\})/g, "\\{");
       } else if (quoted) {
         result = result.replace(/'/g, `'\\''`);
       }
    @@ -101,6 +103,7 @@ function escapeArgZsh(arg, interpolation, quoted) {
       if (interpolation) {
         result = result
           .replace(/\\/g, "\\\\")
    +      .replace(/\n/g, " ")
           .replace(/(^|\s)(~|#|=)/g, "$1\\$2")
           .replace(/(\*|\?)/g, "\\$1")
           .replace(/(\$|\;|\&|\|)/g, "\\$1")
    
  • src/win.js+2 1 modified
    @@ -33,7 +33,7 @@ const binPowerShell = "powershell.exe";
      * @returns {string} The escaped argument.
      */
     function escapeArgCmd(arg, interpolation, quoted) {
    -  let result = arg.replace(/\u0000/g, "");
    +  let result = arg.replace(/\u0000/g, "").replace(/\n|\r/g, " ");
     
       if (interpolation) {
         result = result
    @@ -64,6 +64,7 @@ function escapeArgPowerShell(arg, interpolation, quoted) {
     
       if (interpolation) {
         result = result
    +      .replace(/\n|\r/g, " ")
           .replace(/(^|\s)((?:\*|[1-6])?)(>)/g, "$1$2`$3")
           .replace(/(^|\s)(<|@|#|-|\:|\])/g, "$1`$2")
           .replace(/(,|\;|\&|\|)/g, "`$1")
    
  • test/fixtures/unix.cjs+684 0 modified
    @@ -30,6 +30,172 @@ module.exports.escape = {
             expected: { interpolation: "abc", noInterpolation: "abc" },
           },
         ],
    +    "whitespace (\\s)": [
    +      {
    +        input: "foo	bar",
    +        expected: { interpolation: "foo	bar", noInterpolation: "foo	bar" },
    +      },
    +      {
    +        input: "foo\nbar",
    +        expected: { interpolation: "foo bar", noInterpolation: "foo\nbar" },
    +      },
    +      {
    +        input: "foo\vbar",
    +        expected: { interpolation: "foo\vbar", noInterpolation: "foo\vbar" },
    +      },
    +      {
    +        input: "foo\fbar",
    +        expected: { interpolation: "foo\fbar", noInterpolation: "foo\fbar" },
    +      },
    +      {
    +        input: "foo\rbar",
    +        expected: { interpolation: "foo\rbar", noInterpolation: "foo\rbar" },
    +      },
    +      {
    +        input: "foo bar",
    +        expected: { interpolation: "foo bar", noInterpolation: "foo bar" },
    +      },
    +      {
    +        input: "foo\u0085bar",
    +        expected: {
    +          interpolation: "foo\u0085bar",
    +          noInterpolation: "foo\u0085bar",
    +        },
    +      },
    +      {
    +        input: "foo\u00A0bar",
    +        expected: {
    +          interpolation: "foo\u00A0bar",
    +          noInterpolation: "foo\u00A0bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2000bar",
    +        expected: {
    +          interpolation: "foo\u2000bar",
    +          noInterpolation: "foo\u2000bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2001bar",
    +        expected: {
    +          interpolation: "foo\u2001bar",
    +          noInterpolation: "foo\u2001bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2002bar",
    +        expected: {
    +          interpolation: "foo\u2002bar",
    +          noInterpolation: "foo\u2002bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2003bar",
    +        expected: {
    +          interpolation: "foo\u2003bar",
    +          noInterpolation: "foo\u2003bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2004bar",
    +        expected: {
    +          interpolation: "foo\u2004bar",
    +          noInterpolation: "foo\u2004bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2005bar",
    +        expected: {
    +          interpolation: "foo\u2005bar",
    +          noInterpolation: "foo\u2005bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2006bar",
    +        expected: {
    +          interpolation: "foo\u2006bar",
    +          noInterpolation: "foo\u2006bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2007bar",
    +        expected: {
    +          interpolation: "foo\u2007bar",
    +          noInterpolation: "foo\u2007bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2008bar",
    +        expected: {
    +          interpolation: "foo\u2008bar",
    +          noInterpolation: "foo\u2008bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2009bar",
    +        expected: {
    +          interpolation: "foo\u2009bar",
    +          noInterpolation: "foo\u2009bar",
    +        },
    +      },
    +      {
    +        input: "foo\u200Abar",
    +        expected: {
    +          interpolation: "foo\u200Abar",
    +          noInterpolation: "foo\u200Abar",
    +        },
    +      },
    +      {
    +        input: "foo\u2028bar",
    +        expected: {
    +          interpolation: "foo\u2028bar",
    +          noInterpolation: "foo\u2028bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2029bar",
    +        expected: {
    +          interpolation: "foo\u2029bar",
    +          noInterpolation: "foo\u2029bar",
    +        },
    +      },
    +      {
    +        input: "foo\u202Fbar",
    +        expected: {
    +          interpolation: "foo\u202Fbar",
    +          noInterpolation: "foo\u202Fbar",
    +        },
    +      },
    +      {
    +        input: "foo\u205Fbar",
    +        expected: {
    +          interpolation: "foo\u205Fbar",
    +          noInterpolation: "foo\u205Fbar",
    +        },
    +      },
    +      {
    +        input: "foo\u3000bar",
    +        expected: {
    +          interpolation: "foo\u3000bar",
    +          noInterpolation: "foo\u3000bar",
    +        },
    +      },
    +      {
    +        input: "foo\uFEFFbar",
    +        expected: {
    +          interpolation: "foo\uFEFFbar",
    +          noInterpolation: "foo\uFEFFbar",
    +        },
    +      },
    +      {
    +        input: "foo\n\rbar",
    +        expected: {
    +          interpolation: "foo \rbar",
    +          noInterpolation: "foo\n\rbar",
    +        },
    +      },
    +    ],
         'single quotes ("\'")': [
           {
             input: "a'b",
    @@ -137,6 +303,24 @@ module.exports.escape = {
             input: "a=b:~:",
             expected: { interpolation: "a=b:\\~:", noInterpolation: "a=b:~:" },
           },
    +      {
    +        input: "a=\r:~:",
    +        expected: { interpolation: "a=\r:\\~:", noInterpolation: "a=\r:~:" },
    +      },
    +      {
    +        input: "a=\u2028:~:",
    +        expected: {
    +          interpolation: "a=\u2028:\\~:",
    +          noInterpolation: "a=\u2028:~:",
    +        },
    +      },
    +      {
    +        input: "a=\u2029:~:",
    +        expected: {
    +          interpolation: "a=\u2029:\\~:",
    +          noInterpolation: "a=\u2029:~:",
    +        },
    +      },
           {
             input: "a=b:~:c",
             expected: { interpolation: "a=b:\\~:c", noInterpolation: "a=b:~:c" },
    @@ -391,6 +575,90 @@ module.exports.escape = {
             input: "a{0..2}b",
             expected: { interpolation: "a\\{0..2}b", noInterpolation: "a{0..2}b" },
           },
    +      {
    +        input: "a{\u000Db,c}d",
    +        expected: {
    +          interpolation: "a\\{\u000Db,c}d",
    +          noInterpolation: "a{\u000Db,c}d",
    +        },
    +      },
    +      {
    +        input: "a{\u2028b,c}d",
    +        expected: {
    +          interpolation: "a\\{\u2028b,c}d",
    +          noInterpolation: "a{\u2028b,c}d",
    +        },
    +      },
    +      {
    +        input: "a{\u2029b,c}d",
    +        expected: {
    +          interpolation: "a\\{\u2029b,c}d",
    +          noInterpolation: "a{\u2029b,c}d",
    +        },
    +      },
    +      {
    +        input: "a{b,c\u000D}d",
    +        expected: {
    +          interpolation: "a\\{b,c\u000D}d",
    +          noInterpolation: "a{b,c\u000D}d",
    +        },
    +      },
    +      {
    +        input: "a{b,c\u2028}d",
    +        expected: {
    +          interpolation: "a\\{b,c\u2028}d",
    +          noInterpolation: "a{b,c\u2028}d",
    +        },
    +      },
    +      {
    +        input: "a{b,c\u2029}d",
    +        expected: {
    +          interpolation: "a\\{b,c\u2029}d",
    +          noInterpolation: "a{b,c\u2029}d",
    +        },
    +      },
    +      {
    +        input: "a{\u000D0..2}b",
    +        expected: {
    +          interpolation: "a\\{\u000D0..2}b",
    +          noInterpolation: "a{\u000D0..2}b",
    +        },
    +      },
    +      {
    +        input: "a{\u20280..2}b",
    +        expected: {
    +          interpolation: "a\\{\u20280..2}b",
    +          noInterpolation: "a{\u20280..2}b",
    +        },
    +      },
    +      {
    +        input: "a{\u20290..2}b",
    +        expected: {
    +          interpolation: "a\\{\u20290..2}b",
    +          noInterpolation: "a{\u20290..2}b",
    +        },
    +      },
    +      {
    +        input: "a{0..2\u000D}b",
    +        expected: {
    +          interpolation: "a\\{0..2\u000D}b",
    +          noInterpolation: "a{0..2\u000D}b",
    +        },
    +      },
    +      {
    +        input: "a{0..2\u2028}b",
    +        expected: {
    +          interpolation: "a\\{0..2\u2028}b",
    +          noInterpolation: "a{0..2\u2028}b",
    +        },
    +      },
    +      {
    +        input: "a{0..2\u2029}b",
    +        expected: {
    +          interpolation: "a\\{0..2\u2029}b",
    +          noInterpolation: "a{0..2\u2029}b",
    +        },
    +      },
         ],
         "angle brackets ('<', '>')": [
           {
    @@ -439,6 +707,172 @@ module.exports.escape = {
             expected: { interpolation: "abc", noInterpolation: "abc" },
           },
         ],
    +    "whitespace (\\s)": [
    +      {
    +        input: "foo	bar",
    +        expected: { interpolation: "foo	bar", noInterpolation: "foo	bar" },
    +      },
    +      {
    +        input: "foo\nbar",
    +        expected: { interpolation: "foo bar", noInterpolation: "foo\nbar" },
    +      },
    +      {
    +        input: "foo\vbar",
    +        expected: { interpolation: "foo\vbar", noInterpolation: "foo\vbar" },
    +      },
    +      {
    +        input: "foo\fbar",
    +        expected: { interpolation: "foo\fbar", noInterpolation: "foo\fbar" },
    +      },
    +      {
    +        input: "foo\rbar",
    +        expected: { interpolation: "foo\rbar", noInterpolation: "foo\rbar" },
    +      },
    +      {
    +        input: "foo bar",
    +        expected: { interpolation: "foo bar", noInterpolation: "foo bar" },
    +      },
    +      {
    +        input: "foo\u0085bar",
    +        expected: {
    +          interpolation: "foo\u0085bar",
    +          noInterpolation: "foo\u0085bar",
    +        },
    +      },
    +      {
    +        input: "foo\u00A0bar",
    +        expected: {
    +          interpolation: "foo\u00A0bar",
    +          noInterpolation: "foo\u00A0bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2000bar",
    +        expected: {
    +          interpolation: "foo\u2000bar",
    +          noInterpolation: "foo\u2000bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2001bar",
    +        expected: {
    +          interpolation: "foo\u2001bar",
    +          noInterpolation: "foo\u2001bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2002bar",
    +        expected: {
    +          interpolation: "foo\u2002bar",
    +          noInterpolation: "foo\u2002bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2003bar",
    +        expected: {
    +          interpolation: "foo\u2003bar",
    +          noInterpolation: "foo\u2003bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2004bar",
    +        expected: {
    +          interpolation: "foo\u2004bar",
    +          noInterpolation: "foo\u2004bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2005bar",
    +        expected: {
    +          interpolation: "foo\u2005bar",
    +          noInterpolation: "foo\u2005bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2006bar",
    +        expected: {
    +          interpolation: "foo\u2006bar",
    +          noInterpolation: "foo\u2006bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2007bar",
    +        expected: {
    +          interpolation: "foo\u2007bar",
    +          noInterpolation: "foo\u2007bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2008bar",
    +        expected: {
    +          interpolation: "foo\u2008bar",
    +          noInterpolation: "foo\u2008bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2009bar",
    +        expected: {
    +          interpolation: "foo\u2009bar",
    +          noInterpolation: "foo\u2009bar",
    +        },
    +      },
    +      {
    +        input: "foo\u200Abar",
    +        expected: {
    +          interpolation: "foo\u200Abar",
    +          noInterpolation: "foo\u200Abar",
    +        },
    +      },
    +      {
    +        input: "foo\u2028bar",
    +        expected: {
    +          interpolation: "foo\u2028bar",
    +          noInterpolation: "foo\u2028bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2029bar",
    +        expected: {
    +          interpolation: "foo\u2029bar",
    +          noInterpolation: "foo\u2029bar",
    +        },
    +      },
    +      {
    +        input: "foo\u202Fbar",
    +        expected: {
    +          interpolation: "foo\u202Fbar",
    +          noInterpolation: "foo\u202Fbar",
    +        },
    +      },
    +      {
    +        input: "foo\u205Fbar",
    +        expected: {
    +          interpolation: "foo\u205Fbar",
    +          noInterpolation: "foo\u205Fbar",
    +        },
    +      },
    +      {
    +        input: "foo\u3000bar",
    +        expected: {
    +          interpolation: "foo\u3000bar",
    +          noInterpolation: "foo\u3000bar",
    +        },
    +      },
    +      {
    +        input: "foo\uFEFFbar",
    +        expected: {
    +          interpolation: "foo\uFEFFbar",
    +          noInterpolation: "foo\uFEFFbar",
    +        },
    +      },
    +      {
    +        input: "foo\n\rbar",
    +        expected: {
    +          interpolation: "foo \rbar",
    +          noInterpolation: "foo\n\rbar",
    +        },
    +      },
    +    ],
         'single quotes ("\'")': [
           {
             input: "a'b",
    @@ -800,6 +1234,90 @@ module.exports.escape = {
             input: "a{0..2}b",
             expected: { interpolation: "a\\{0..2}b", noInterpolation: "a{0..2}b" },
           },
    +      {
    +        input: "a{\u000Db,c}d",
    +        expected: {
    +          interpolation: "a\\{\u000Db,c}d",
    +          noInterpolation: "a{\u000Db,c}d",
    +        },
    +      },
    +      {
    +        input: "a{\u2028b,c}d",
    +        expected: {
    +          interpolation: "a\\{\u2028b,c}d",
    +          noInterpolation: "a{\u2028b,c}d",
    +        },
    +      },
    +      {
    +        input: "a{\u2029b,c}d",
    +        expected: {
    +          interpolation: "a\\{\u2029b,c}d",
    +          noInterpolation: "a{\u2029b,c}d",
    +        },
    +      },
    +      {
    +        input: "a{b,c\u000D}d",
    +        expected: {
    +          interpolation: "a\\{b,c\u000D}d",
    +          noInterpolation: "a{b,c\u000D}d",
    +        },
    +      },
    +      {
    +        input: "a{b,c\u2028}d",
    +        expected: {
    +          interpolation: "a\\{b,c\u2028}d",
    +          noInterpolation: "a{b,c\u2028}d",
    +        },
    +      },
    +      {
    +        input: "a{b,c\u2029}d",
    +        expected: {
    +          interpolation: "a\\{b,c\u2029}d",
    +          noInterpolation: "a{b,c\u2029}d",
    +        },
    +      },
    +      {
    +        input: "a{\u000D0..2}b",
    +        expected: {
    +          interpolation: "a\\{\u000D0..2}b",
    +          noInterpolation: "a{\u000D0..2}b",
    +        },
    +      },
    +      {
    +        input: "a{\u20280..2}b",
    +        expected: {
    +          interpolation: "a\\{\u20280..2}b",
    +          noInterpolation: "a{\u20280..2}b",
    +        },
    +      },
    +      {
    +        input: "a{\u20290..2}b",
    +        expected: {
    +          interpolation: "a\\{\u20290..2}b",
    +          noInterpolation: "a{\u20290..2}b",
    +        },
    +      },
    +      {
    +        input: "a{0..2\u000D}b",
    +        expected: {
    +          interpolation: "a\\{0..2\u000D}b",
    +          noInterpolation: "a{0..2\u000D}b",
    +        },
    +      },
    +      {
    +        input: "a{0..2\u2028}b",
    +        expected: {
    +          interpolation: "a\\{0..2\u2028}b",
    +          noInterpolation: "a{0..2\u2028}b",
    +        },
    +      },
    +      {
    +        input: "a{0..2\u2029}b",
    +        expected: {
    +          interpolation: "a\\{0..2\u2029}b",
    +          noInterpolation: "a{0..2\u2029}b",
    +        },
    +      },
         ],
         "angle brackets ('<', '>')": [
           {
    @@ -848,6 +1366,172 @@ module.exports.escape = {
             expected: { interpolation: "abc", noInterpolation: "abc" },
           },
         ],
    +    "whitespace (\\s)": [
    +      {
    +        input: "foo	bar",
    +        expected: { interpolation: "foo	bar", noInterpolation: "foo	bar" },
    +      },
    +      {
    +        input: "foo\nbar",
    +        expected: { interpolation: "foo bar", noInterpolation: "foo\nbar" },
    +      },
    +      {
    +        input: "foo\vbar",
    +        expected: { interpolation: "foo\vbar", noInterpolation: "foo\vbar" },
    +      },
    +      {
    +        input: "foo\fbar",
    +        expected: { interpolation: "foo\fbar", noInterpolation: "foo\fbar" },
    +      },
    +      {
    +        input: "foo\rbar",
    +        expected: { interpolation: "foo\rbar", noInterpolation: "foo\rbar" },
    +      },
    +      {
    +        input: "foo bar",
    +        expected: { interpolation: "foo bar", noInterpolation: "foo bar" },
    +      },
    +      {
    +        input: "foo\u0085bar",
    +        expected: {
    +          interpolation: "foo\u0085bar",
    +          noInterpolation: "foo\u0085bar",
    +        },
    +      },
    +      {
    +        input: "foo\u00A0bar",
    +        expected: {
    +          interpolation: "foo\u00A0bar",
    +          noInterpolation: "foo\u00A0bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2000bar",
    +        expected: {
    +          interpolation: "foo\u2000bar",
    +          noInterpolation: "foo\u2000bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2001bar",
    +        expected: {
    +          interpolation: "foo\u2001bar",
    +          noInterpolation: "foo\u2001bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2002bar",
    +        expected: {
    +          interpolation: "foo\u2002bar",
    +          noInterpolation: "foo\u2002bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2003bar",
    +        expected: {
    +          interpolation: "foo\u2003bar",
    +          noInterpolation: "foo\u2003bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2004bar",
    +        expected: {
    +          interpolation: "foo\u2004bar",
    +          noInterpolation: "foo\u2004bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2005bar",
    +        expected: {
    +          interpolation: "foo\u2005bar",
    +          noInterpolation: "foo\u2005bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2006bar",
    +        expected: {
    +          interpolation: "foo\u2006bar",
    +          noInterpolation: "foo\u2006bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2007bar",
    +        expected: {
    +          interpolation: "foo\u2007bar",
    +          noInterpolation: "foo\u2007bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2008bar",
    +        expected: {
    +          interpolation: "foo\u2008bar",
    +          noInterpolation: "foo\u2008bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2009bar",
    +        expected: {
    +          interpolation: "foo\u2009bar",
    +          noInterpolation: "foo\u2009bar",
    +        },
    +      },
    +      {
    +        input: "foo\u200Abar",
    +        expected: {
    +          interpolation: "foo\u200Abar",
    +          noInterpolation: "foo\u200Abar",
    +        },
    +      },
    +      {
    +        input: "foo\u2028bar",
    +        expected: {
    +          interpolation: "foo\u2028bar",
    +          noInterpolation: "foo\u2028bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2029bar",
    +        expected: {
    +          interpolation: "foo\u2029bar",
    +          noInterpolation: "foo\u2029bar",
    +        },
    +      },
    +      {
    +        input: "foo\u202Fbar",
    +        expected: {
    +          interpolation: "foo\u202Fbar",
    +          noInterpolation: "foo\u202Fbar",
    +        },
    +      },
    +      {
    +        input: "foo\u205Fbar",
    +        expected: {
    +          interpolation: "foo\u205Fbar",
    +          noInterpolation: "foo\u205Fbar",
    +        },
    +      },
    +      {
    +        input: "foo\u3000bar",
    +        expected: {
    +          interpolation: "foo\u3000bar",
    +          noInterpolation: "foo\u3000bar",
    +        },
    +      },
    +      {
    +        input: "foo\uFEFFbar",
    +        expected: {
    +          interpolation: "foo\uFEFFbar",
    +          noInterpolation: "foo\uFEFFbar",
    +        },
    +      },
    +      {
    +        input: "foo\n\rbar",
    +        expected: {
    +          interpolation: "foo \rbar",
    +          noInterpolation: "foo\n\rbar",
    +        },
    +      },
    +    ],
         'single quotes ("\'")': [
           {
             input: "a'b",
    
  • test/fixtures/win.cjs+346 0 modified
    @@ -30,6 +30,179 @@ module.exports.escape = {
             expected: { interpolation: "abc", noInterpolation: "abc" },
           },
         ],
    +    "whitespace (\\s)": [
    +      {
    +        input: "foo	bar",
    +        expected: { interpolation: "foo	bar", noInterpolation: "foo	bar" },
    +      },
    +      {
    +        input: "foo\nbar",
    +        expected: { interpolation: "foo bar", noInterpolation: "foo bar" },
    +      },
    +      {
    +        input: "foo\vbar",
    +        expected: { interpolation: "foo\vbar", noInterpolation: "foo\vbar" },
    +      },
    +      {
    +        input: "foo\fbar",
    +        expected: { interpolation: "foo\fbar", noInterpolation: "foo\fbar" },
    +      },
    +      {
    +        input: "foo\rbar",
    +        expected: { interpolation: "foo bar", noInterpolation: "foo bar" },
    +      },
    +      {
    +        input: "foo bar",
    +        expected: { interpolation: "foo bar", noInterpolation: "foo bar" },
    +      },
    +      {
    +        input: "foo\u0085bar",
    +        expected: {
    +          interpolation: "foo\u0085bar",
    +          noInterpolation: "foo\u0085bar",
    +        },
    +      },
    +      {
    +        input: "foo\u00A0bar",
    +        expected: {
    +          interpolation: "foo\u00A0bar",
    +          noInterpolation: "foo\u00A0bar",
    +        },
    +      },
    +      {
    +        input: "foo\u1680bar",
    +        expected: {
    +          interpolation: "foo\u1680bar",
    +          noInterpolation: "foo\u1680bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2000bar",
    +        expected: {
    +          interpolation: "foo\u2000bar",
    +          noInterpolation: "foo\u2000bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2001bar",
    +        expected: {
    +          interpolation: "foo\u2001bar",
    +          noInterpolation: "foo\u2001bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2002bar",
    +        expected: {
    +          interpolation: "foo\u2002bar",
    +          noInterpolation: "foo\u2002bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2003bar",
    +        expected: {
    +          interpolation: "foo\u2003bar",
    +          noInterpolation: "foo\u2003bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2004bar",
    +        expected: {
    +          interpolation: "foo\u2004bar",
    +          noInterpolation: "foo\u2004bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2005bar",
    +        expected: {
    +          interpolation: "foo\u2005bar",
    +          noInterpolation: "foo\u2005bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2006bar",
    +        expected: {
    +          interpolation: "foo\u2006bar",
    +          noInterpolation: "foo\u2006bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2007bar",
    +        expected: {
    +          interpolation: "foo\u2007bar",
    +          noInterpolation: "foo\u2007bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2008bar",
    +        expected: {
    +          interpolation: "foo\u2008bar",
    +          noInterpolation: "foo\u2008bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2009bar",
    +        expected: {
    +          interpolation: "foo\u2009bar",
    +          noInterpolation: "foo\u2009bar",
    +        },
    +      },
    +      {
    +        input: "foo\u200Abar",
    +        expected: {
    +          interpolation: "foo\u200Abar",
    +          noInterpolation: "foo\u200Abar",
    +        },
    +      },
    +      {
    +        input: "foo\u2028bar",
    +        expected: {
    +          interpolation: "foo\u2028bar",
    +          noInterpolation: "foo\u2028bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2029bar",
    +        expected: {
    +          interpolation: "foo\u2029bar",
    +          noInterpolation: "foo\u2029bar",
    +        },
    +      },
    +      {
    +        input: "foo\u202Fbar",
    +        expected: {
    +          interpolation: "foo\u202Fbar",
    +          noInterpolation: "foo\u202Fbar",
    +        },
    +      },
    +      {
    +        input: "foo\u205Fbar",
    +        expected: {
    +          interpolation: "foo\u205Fbar",
    +          noInterpolation: "foo\u205Fbar",
    +        },
    +      },
    +      {
    +        input: "foo\u3000bar",
    +        expected: {
    +          interpolation: "foo\u3000bar",
    +          noInterpolation: "foo\u3000bar",
    +        },
    +      },
    +      {
    +        input: "foo\uFEFFbar",
    +        expected: {
    +          interpolation: "foo\uFEFFbar",
    +          noInterpolation: "foo\uFEFFbar",
    +        },
    +      },
    +      {
    +        input: "foo\n\rbar",
    +        expected: {
    +          interpolation: "foo  bar",
    +          noInterpolation: "foo  bar",
    +        },
    +      },
    +    ],
         'single quotes ("\'")': [
           {
             input: "a'b",
    @@ -399,6 +572,179 @@ module.exports.escape = {
             expected: { interpolation: "abc", noInterpolation: "abc" },
           },
         ],
    +    "whitespace (\\s)": [
    +      {
    +        input: "foo	bar",
    +        expected: { interpolation: "foo	bar", noInterpolation: "foo	bar" },
    +      },
    +      {
    +        input: "foo\nbar",
    +        expected: { interpolation: "foo bar", noInterpolation: "foo\nbar" },
    +      },
    +      {
    +        input: "foo\vbar",
    +        expected: { interpolation: "foo\vbar", noInterpolation: "foo\vbar" },
    +      },
    +      {
    +        input: "foo\fbar",
    +        expected: { interpolation: "foo\fbar", noInterpolation: "foo\fbar" },
    +      },
    +      {
    +        input: "foo\rbar",
    +        expected: { interpolation: "foo bar", noInterpolation: "foo\rbar" },
    +      },
    +      {
    +        input: "foo bar",
    +        expected: { interpolation: "foo bar", noInterpolation: "foo bar" },
    +      },
    +      {
    +        input: "foo\u0085bar",
    +        expected: {
    +          interpolation: "foo\u0085bar",
    +          noInterpolation: "foo\u0085bar",
    +        },
    +      },
    +      {
    +        input: "foo\u00A0bar",
    +        expected: {
    +          interpolation: "foo\u00A0bar",
    +          noInterpolation: "foo\u00A0bar",
    +        },
    +      },
    +      {
    +        input: "foo\u1680bar",
    +        expected: {
    +          interpolation: "foo\u1680bar",
    +          noInterpolation: "foo\u1680bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2000bar",
    +        expected: {
    +          interpolation: "foo\u2000bar",
    +          noInterpolation: "foo\u2000bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2001bar",
    +        expected: {
    +          interpolation: "foo\u2001bar",
    +          noInterpolation: "foo\u2001bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2002bar",
    +        expected: {
    +          interpolation: "foo\u2002bar",
    +          noInterpolation: "foo\u2002bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2003bar",
    +        expected: {
    +          interpolation: "foo\u2003bar",
    +          noInterpolation: "foo\u2003bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2004bar",
    +        expected: {
    +          interpolation: "foo\u2004bar",
    +          noInterpolation: "foo\u2004bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2005bar",
    +        expected: {
    +          interpolation: "foo\u2005bar",
    +          noInterpolation: "foo\u2005bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2006bar",
    +        expected: {
    +          interpolation: "foo\u2006bar",
    +          noInterpolation: "foo\u2006bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2007bar",
    +        expected: {
    +          interpolation: "foo\u2007bar",
    +          noInterpolation: "foo\u2007bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2008bar",
    +        expected: {
    +          interpolation: "foo\u2008bar",
    +          noInterpolation: "foo\u2008bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2009bar",
    +        expected: {
    +          interpolation: "foo\u2009bar",
    +          noInterpolation: "foo\u2009bar",
    +        },
    +      },
    +      {
    +        input: "foo\u200Abar",
    +        expected: {
    +          interpolation: "foo\u200Abar",
    +          noInterpolation: "foo\u200Abar",
    +        },
    +      },
    +      {
    +        input: "foo\u2028bar",
    +        expected: {
    +          interpolation: "foo\u2028bar",
    +          noInterpolation: "foo\u2028bar",
    +        },
    +      },
    +      {
    +        input: "foo\u2029bar",
    +        expected: {
    +          interpolation: "foo\u2029bar",
    +          noInterpolation: "foo\u2029bar",
    +        },
    +      },
    +      {
    +        input: "foo\u202Fbar",
    +        expected: {
    +          interpolation: "foo\u202Fbar",
    +          noInterpolation: "foo\u202Fbar",
    +        },
    +      },
    +      {
    +        input: "foo\u205Fbar",
    +        expected: {
    +          interpolation: "foo\u205Fbar",
    +          noInterpolation: "foo\u205Fbar",
    +        },
    +      },
    +      {
    +        input: "foo\u3000bar",
    +        expected: {
    +          interpolation: "foo\u3000bar",
    +          noInterpolation: "foo\u3000bar",
    +        },
    +      },
    +      {
    +        input: "foo\uFEFFbar",
    +        expected: {
    +          interpolation: "foo\uFEFFbar",
    +          noInterpolation: "foo\uFEFFbar",
    +        },
    +      },
    +      {
    +        input: "foo\n\rbar",
    +        expected: {
    +          interpolation: "foo  bar",
    +          noInterpolation: "foo\n\rbar",
    +        },
    +      },
    +    ],
         'single quotes ("\'")': [
           {
             input: "a'b",
    
  • test/fuzz/_common.cjs+20 17 modified
    @@ -25,26 +25,35 @@ function isShellPowerShell(shell) {
     }
     
     function getExpectedOutput({ arg, shell }, normalizeWhitespace) {
    -  if (isShellCmd(shell)) {
    -    arg = arg.replace(/[\n\r]+/g, ""); // Remove newline characters, like prep
    -  }
    -
       arg = arg.replace(/\u{0}/gu, ""); // Remove null characters, like Shescape
     
       if (normalizeWhitespace) {
    -    // The characters to normalize depend on the shell
    -    // Trim the string like any shell would
    +    // Trim the string, like the shell
         if (isShellPowerShell(shell)) {
    -      arg = arg.replace(/^[\s\u0085]+|[\s\u0085]+$/g, "");
    +      arg = arg.replace(
    +        /^[ \t\n\v\f\r\u0085\u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]+|[ \t\n\v\f\r\u0085\u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]+$/g,
    +        ""
    +      );
    +    } else if (isShellCmd(shell)) {
    +      arg = arg.replace(/^[ \t\n\r]+|[ \t\n\r]+$/g, "");
         } else {
    -      arg = arg.replace(/^[ \t]+|[ \t]+$/g, "");
    +      arg = arg.replace(/^[ \t\n]+|[ \t\n]+$/g, "");
         }
     
    -    // Convert spacing between arguments to a single space, like the shell would
    +    // Convert spacing between arguments to a single space, like the shell
         if (isShellPowerShell(shell)) {
    -      arg = arg.replace(/(\s|\u0085)+/g, " ");
    +      arg = arg.replace(
    +        /[ \t\n\v\f\r\u0085\u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]+/g,
    +        " "
    +      );
    +    } else if (isShellCmd(shell)) {
    +      arg = arg.replace(/[ \t\n\r]+/g, " ");
         } else {
    -      arg = arg.replace(/[ \t]+/g, " ");
    +      arg = arg.replace(/[ \t\n]+/g, " ");
    +    }
    +  } else {
    +    if (isShellCmd(shell)) {
    +      arg = arg.replace(/[\n\r]/g, " "); // Change newlines to spaces, like Shescape
         }
       }
     
    @@ -57,12 +66,6 @@ function getFuzzShell() {
     }
     
     function prepareArg({ arg, quoted, shell }, disableExtraWindowsPreparations) {
    -  if (isShellCmd(shell)) {
    -    // In CMD ignores everything after a newline (\n) character. This alteration
    -    // is required even when `disableExtraWindowsPreparations` is true.
    -    arg = arg.replace(/[\n\r]+/g, "");
    -  }
    -
       if (isWindows() && !disableExtraWindowsPreparations) {
         // Node on Windows ...
         if (isShellCmd(shell)) {
    
  • test/fuzz/corpus/036053b103374e82177446b4e083ccb6a22da06e0375582d622632775c8a938a+1 0 added
    @@ -0,0 +1 @@
    +
    �
    \ No newline at end of file
    
  • test/fuzz/corpus/31ed7643aba69fe2d776af3aee587bb7899165af5ed3846c6f70327f2eec4713+1 0 added
    @@ -0,0 +1 @@
    +u�0:�\(?\
    
    \ No newline at end of file
    
  • test/fuzz/corpus/7ef6c55f814adceff17a05c032ba6ec89483e37addcfd96bd13281f5de6716fa+1 0 added
    @@ -0,0 +1 @@
    +!�! �
    
  • test/fuzz/corpus/dece2a606846120af17949c2d758b7df475449689d043a04a1ba63953326e5bb+2 0 added
    @@ -0,0 +1,2 @@
    +foo=
    +:~
    
  • test/fuzz/corpus/f1d97ce94d0c9dd109dc27538786781da634bbed1df58877cac3c44e4344f3dd+1 0 added
    @@ -0,0 +1 @@
    +#� 
    ��"3dw��
    \ No newline at end of file
    
  • test/fuzz/corpus/f28febc41472c437122c2a44b66ccf7dcefdd19876fe4d9370ece44b5b2deb13+1 0 added
    @@ -0,0 +1 @@
    +q=�
    �3�[�:~
    \ No newline at end of file
    
  • test/fuzz/corpus/faf3c25ec7c017c2cc21a5af0f5584557d8a0c7340c68249076a86a2c4ce74fb+2 0 added
    @@ -0,0 +1,2 @@
    +a{
    +b,c}d
    
  • test/fuzz/exec.test.cjs+0 4 modified
    @@ -43,8 +43,6 @@ function checkWithShell(arg) {
     }
     
     function checkWithoutShellUsingInterpolation(arg) {
    -  arg = arg.replace(/[\n\r]+/g, "");
    -
       const argInfo = { arg, shell: undefined, quoted: false };
     
       const preparedArg = common.prepareArg(argInfo);
    @@ -60,8 +58,6 @@ function checkWithoutShellUsingInterpolation(arg) {
     }
     
     function checkWithShellUsingInterpolation(arg) {
    -  arg = arg.replace(/[\n\r]+/g, "");
    -
       const shell = common.getFuzzShell() || true;
       const argInfo = { arg, shell, quoted: false };
       const execOptions = { shell };
    
  • test/unit/_macros.js+27 1 modified
    @@ -28,7 +28,33 @@ export const escape = test.macro({
         t.is(actual, expected);
       },
       title(_, { input, interpolation, quoted, shellName }) {
    -    input = input.replace(/\u{0}/gu, "\\x00").replace(/\t/g, "\\t");
    +    input = input
    +      .replace(/\u0000/g, "\\u{0000}")
    +      .replace(/\u0009/g, "\\t")
    +      .replace(/\u000A/g, "\\n")
    +      .replace(/\u000B/g, "\\v")
    +      .replace(/\u000C/g, "\\f")
    +      .replace(/\u000D/g, "\\r")
    +      .replace(/\u0085/g, "\\u{0085}")
    +      .replace(/\u00A0/g, "\\u{00A0}")
    +      .replace(/\u1680/g, "\\u{1680}")
    +      .replace(/\u2000/g, "\\u{2000}")
    +      .replace(/\u2001/g, "\\u{2001}")
    +      .replace(/\u2002/g, "\\u{2002}")
    +      .replace(/\u2003/g, "\\u{2003}")
    +      .replace(/\u2004/g, "\\u{2004}")
    +      .replace(/\u2005/g, "\\u{2005}")
    +      .replace(/\u2006/g, "\\u{2006}")
    +      .replace(/\u2007/g, "\\u{2007}")
    +      .replace(/\u2008/g, "\\u{2008}")
    +      .replace(/\u2009/g, "\\u{2009}")
    +      .replace(/\u200A/g, "\\u{200A}")
    +      .replace(/\u2028/g, "\\u{2028}")
    +      .replace(/\u2029/g, "\\u{2029}")
    +      .replace(/\u202F/g, "\\u{202F}")
    +      .replace(/\u205F/g, "\\u{205F}")
    +      .replace(/\u3000/g, "\\u{3000}")
    +      .replace(/\uFEFF/g, "\\u{FEFF}");
         interpolation = interpolation ? "interpolation" : "no interpolation";
         quoted = quoted ? "quoted" : "not quoted";
     
    

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.