VYPR
Low severityOSV Advisory· Published Mar 25, 2025· Updated Apr 15, 2026

CVE-2025-30222

CVE-2025-30222

Description

Shescape is a simple shell escape library for JavaScript. Versions 1.7.2 through 2.1.1 are vulnerable to potential environment variable exposure on Windows with CMD. This impact users of Shescape on Windows that explicitly configure shell: 'cmd.exe' or shell: true using any of quote/quoteAll/escape/escapeAll. An attacker may be able to get read-only access to environment variables. This bug has been patched in v2.1.2. For those who are already using v2 of Shescape, no further changes are required. Those who are are using v1 of Shescape should follow the migration guide to upgrade to v2. There is no plan to release a patch compatible with v1 of Shescape. As a workaround, users can remove all instances of % from user input before using Shescape.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
shescapenpm
>= 1.7.2, < 2.1.22.1.2

Affected products

1

Patches

2
0a81f1eb077b

Correct escaping of `%` escaping for CMD (#1916)

https://github.com/ericcornelissen/shescapeEric CornelissenMar 25, 2025via ghsa
4 files changed · +54 70
  • CHANGELOG.md+2 1 modified
    @@ -9,7 +9,7 @@ Versioning].
     
     ## [Unreleased]
     
    -- _No changes yet_
    +- Correct escaping of `%` escaping for CMD. ([#1916])
     
     ## [2.1.1] - 2024-05-01
     
    @@ -340,6 +340,7 @@ Versioning].
     [#1308]: https://github.com/ericcornelissen/shescape/pull/1308
     [#1530]: https://github.com/ericcornelissen/shescape/pull/1530
     [#1536]: https://github.com/ericcornelissen/shescape/pull/1536
    +[#1916]: https://github.com/ericcornelissen/shescape/pull/1916
     [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/win/cmd.js+1 19 modified
    @@ -10,29 +10,11 @@
      * @returns {string} The escaped argument.
      */
     function escapeArg(arg) {
    -  let shouldEscapeSpecialChar = true;
       return arg
         .replace(/[\0\u0008\r\u001B\u009B]/gu, "")
         .replace(/\n/gu, " ")
         .replace(/(?<!\\)(\\*)"/gu, '$1$1\\"')
    -    .split("")
    -    .map(
    -      // Due to the way CMD determines if it is inside a quoted section, and the
    -      // way we escape double quotes, whether or not special character need to
    -      // be escaped depends on the number of double quotes that proceed it. So,
    -      // we flip a flag for every double quote we encounter and escape special
    -      // characters conditionally on that flag.
    -      (char) => {
    -        if (char === '"') {
    -          shouldEscapeSpecialChar = !shouldEscapeSpecialChar;
    -        } else if (shouldEscapeSpecialChar && /[%&<>^|]/u.test(char)) {
    -          return `^${char}`;
    -        }
    -
    -        return char;
    -      },
    -    )
    -    .join("");
    +    .replace(/(["%&<>^|])/gu, "^$1");
     }
     
     /**
    
  • test/fixtures/win.js+50 50 modified
    @@ -1752,19 +1752,19 @@ export const escape = {
         "double quotes ('\"')": [
           {
             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',
           },
         ],
         "backticks ('`')": [
    @@ -1842,15 +1842,15 @@ export const escape = {
         "carets ('^') + double quotes ('\"')": [
           {
             input: 'a"b^c',
    -        expected: 'a\\"b^c',
    +        expected: 'a\\^"b^^c',
           },
           {
             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',
           },
         ],
         "dollar signs ('$')": [
    @@ -1892,15 +1892,15 @@ export const escape = {
         "percentage signs ('%') + double quotes ('\"')": [
           {
             input: 'a"b%c',
    -        expected: 'a\\"b%c',
    +        expected: 'a\\^"b^%c',
           },
           {
             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',
           },
         ],
         "ampersands ('&')": [
    @@ -1924,15 +1924,15 @@ export const escape = {
         "ampersands ('&') + double quotes ('\"')": [
           {
             input: 'a"b&c',
    -        expected: 'a\\"b&c',
    +        expected: 'a\\^"b^&c',
           },
           {
             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',
           },
         ],
         "hyphens ('-')": [
    @@ -2028,15 +2028,15 @@ export const escape = {
         "pipes ('|') + double quotes ('\"')": [
           {
             input: 'a"b|c',
    -        expected: 'a\\"b|c',
    +        expected: 'a\\^"b^|c',
           },
           {
             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',
           },
         ],
         "comma (',')": [
    @@ -2212,27 +2212,27 @@ export const escape = {
         "angle brackets ('<', '>') + double quotes ('\"')": [
           {
             input: 'a"b>c',
    -        expected: 'a\\"b>c',
    +        expected: 'a\\^"b^>c',
           },
           {
             input: 'a"b<c',
    -        expected: 'a\\"b<c',
    +        expected: 'a\\^"b^<c',
           },
           {
             input: 'a"b"c>d',
    -        expected: 'a\\"b\\"c^>d',
    +        expected: 'a\\^"b\\^"c^>d',
           },
           {
             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',
           },
         ],
         "left double quotation mark ('“')": [
    @@ -4490,47 +4490,47 @@ export const quote = {
         "double quotes ('\"')": [
           {
             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',
           },
         ],
         "double quotes ('\"') + whitespace": [
           {
             input: 'a "b',
    -        expected: 'a" "\\"b',
    +        expected: 'a" "\\^"b',
           },
           {
             input: 'a" b',
    -        expected: 'a\\"" "b',
    +        expected: 'a\\^"" "b',
           },
           {
             input: 'a " b',
    -        expected: 'a" "\\"" "b',
    +        expected: 'a" "\\^"" "b',
           },
         ],
         "double quotes ('\"') + backslashes ('\\')": [
           {
             input: 'a\\"b',
    -        expected: 'a\\\\\\"b',
    +        expected: 'a\\\\\\^"b',
           },
           {
             input: 'a\\\\"b',
    -        expected: 'a\\\\\\\\\\"b',
    +        expected: 'a\\\\\\\\\\^"b',
           },
         ],
         "backticks ('`')": [
    @@ -4572,15 +4572,15 @@ export const quote = {
         "carets ('^') + double quotes ('\"')": [
           {
             input: 'a"b^c',
    -        expected: 'a\\"b^c',
    +        expected: 'a\\^"b^^c',
           },
           {
             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',
           },
         ],
         "dollar signs ('$')": [
    @@ -4622,15 +4622,15 @@ export const quote = {
         "percentage signs ('%') + double quotes ('\"')": [
           {
             input: 'a"b%c',
    -        expected: 'a\\"b%c',
    +        expected: 'a\\^"b^%c',
           },
           {
             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',
           },
         ],
         "ampersands ('&')": [
    @@ -4654,15 +4654,15 @@ export const quote = {
         "ampersands ('&') + double quotes ('\"')": [
           {
             input: 'a"b&c',
    -        expected: 'a\\"b&c',
    +        expected: 'a\\^"b^&c',
           },
           {
             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',
           },
         ],
         "hyphens ('-')": [
    @@ -4722,15 +4722,15 @@ export const quote = {
         "pipes ('|') + double quotes ('\"')": [
           {
             input: 'a"b|c',
    -        expected: 'a\\"b|c',
    +        expected: 'a\\^"b^|c',
           },
           {
             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',
           },
         ],
         "angle brackets ('<', '>')": [
    @@ -4774,27 +4774,27 @@ export const quote = {
         "angle brackets ('<', '>') + double quotes ('\"')": [
           {
             input: 'a"b>c',
    -        expected: 'a\\"b>c',
    +        expected: 'a\\^"b^>c',
           },
           {
             input: 'a"b<c',
    -        expected: 'a\\"b<c',
    +        expected: 'a\\^"b^<c',
           },
           {
             input: 'a"b"c>d',
    -        expected: 'a\\"b\\"c^>d',
    +        expected: 'a\\^"b\\^"c^>d',
           },
           {
             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',
           },
         ],
         "left double quotation mark ('“')": [
    
  • test/fuzz/corpus/fc01cea8ecef9dedd1b4d22dde5cb82e90000522+1 0 added
    @@ -0,0 +1 @@
    +"%PATH%
    

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.