{"repro_id":"REPRO-2026-00110","version":6,"title":"Deno Command Injection via Incomplete Metacharacter Blocklist","repro_type":"security","status":"published","severity":"high","description":"A command injection vulnerability exists in Deno's `node:child_process` implementation.","root_cause":"# Root Cause Analysis: GHSA-hmh4-3xvx-q5hr\n\n## Summary\n\nA command injection vulnerability exists in Deno's `node:child_process` implementation (specifically in the `spawnSync` and `spawn` functions). When using `shell: true` option with arguments passed as an array, the arguments were not properly escaped before being joined into a shell command string. This allowed shell metacharacters (particularly newlines `\\n` and carriage returns `\\r`) embedded in argument values to be interpreted by the shell as command separators, enabling arbitrary command execution.\n\n## Impact\n\n- **Package:** deno (Rust-based JavaScript/TypeScript runtime)\n- **Affected Component:** `node:child_process` polyfill (ext/node/polyfills/internal/child_process.ts)\n- **Affected Versions:** < 2.6.8\n- **Patched Version:** 2.6.8\n- **Severity:** HIGH (CVSS 8.1)\n- **Consequences:** Arbitrary code execution when user-controlled input is passed to spawn functions with `shell: true`\n\n## Root Cause\n\nThe vulnerability stems from improper argument escaping in the `normalizeSpawnArguments` function:\n\n1. **Before the fix (v2.6.7 and earlier):**\n   ```typescript\n   if (options.shell) {\n     let command = ArrayPrototypeJoin([file, ...args], \" \");\n     // ...\n   }\n   ```\n   Arguments were simply joined with spaces, making no attempt to escape shell metacharacters.\n\n2. **The fix (commit 9132ad958c83a0d0b199de12b69b877f63edab4c):**\n   - Added `escapeShellArg()` function that properly escapes shell arguments\n   - On Unix: wraps arguments in single quotes and escapes embedded single quotes\n   - On Windows: wraps in double quotes and escapes embedded double quotes and backslashes\n   - Arguments are now escaped before being joined into the shell command\n\n3. **Additional fix:** The shell metacharacter check in `transformDenoShellCommand` was expanded from:\n   ```regex\n   /[();&|<>`!]/\n   ```\n   to:\n   ```regex\n   /[();&|<>`!\\n\\r]/\n   ```\n   This catches newline (`\\n`) and carriage return (`\\r`) characters used for command injection.\n\n## Reproduction Steps\n\n1. Execute `repro/reproduction_steps.sh` which:\n   - Downloads Deno v2.6.7 (vulnerable version)\n   - Creates a PoC that uses `spawnSync` with `shell: true` and a malicious argument containing a newline\n   - The malicious argument: `/tmp/legitimate.ts\\ntouch /tmp/rce_proof`\n   - When the shell interprets this, it executes: `deno run --allow-all /tmp/legitimate.ts` followed by `touch /tmp/rce_proof`\n\n2. **Expected evidence:**\n   - The file `/tmp/rce_proof` is created\n   - Script outputs: \"VULNERABILITY CONFIRMED: Command injection via newline in shell argument\"\n   - Exit code: 0\n\n## Evidence\n\n- **Log files:** `logs/run1.log`, `logs/run2.log`, `logs/result.txt`\n- **Key excerpt from run1.log:**\n  ```\n  Exploit worked: true\n  VULNERABILITY CONFIRMED: Command injection via newline in shell argument\n  \n  === RESULT: VULNERABILITY CONFIRMED ===\n  The newline command injection vulnerability is present in this version.\n  Evidence: /tmp/rce_proof file was created via shell injection.\n  -rw-r--r-- 1 root root 0 Feb 20 14:46 /tmp/rce_proof\n  ```\n- **Environment:** Linux x86_64, Deno 2.6.7\n\n## Recommendations / Next Steps\n\n1. **Immediate action:** Upgrade to Deno v2.6.8 or later\n2. **For developers:** \n   - Avoid using `shell: true` with user-controlled input when possible\n   - If shell features are needed, validate and sanitize all arguments\n   - Use `shell: false` (default) and pass arguments as arrays when shell interpretation is not required\n3. **Testing recommendations:**\n   - Add test cases for shell metacharacter injection: `\\n`, `\\r`, `;`, `|`, `&`, `$()`, backticks, etc.\n   - Test both Unix and Windows platforms (different escaping requirements)\n\n## Additional Notes\n\n- **Idempotency confirmed:** The reproduction script was executed twice consecutively and confirmed the vulnerability both times.\n- **Edge cases:** The vulnerability affects both synchronous (`spawnSync`) and asynchronous (`spawn`) variants of child_process functions.\n- **Platform notes:** While this reproduction was tested on Linux, the same vulnerability exists on Windows with different shell metacharacter behaviors. The fix addresses both platforms with platform-specific escaping logic.\n","ghsa_id":"GHSA-hmh4-3xvx-q5hr","cve_id":"CVE-2026-27190","package":{"name":"deno","ecosystem":"rust","affected_versions":"< 2.6.8","fixed_version":"2.6.8"},"reproduced_at":"2026-02-20T15:03:44.204215+00:00","duration_secs":605.602471113205,"tool_calls":75,"turns":50,"handoffs":2,"total_cost_usd":0.2687734,"agent_costs":{"repro":0.0449359,"support":0.0150347,"vuln_variant":0.2088028},"cost_breakdown":{"repro":{"accounts/fireworks/models/kimi-k2p5":0.0449359},"support":{"accounts/fireworks/models/kimi-k2p5":0.0150347},"vuln_variant":{"accounts/fireworks/models/kimi-k2p5":0.2088028}},"quality":{"idempotent_verified":false,"community_verifications":0},"published_at":"2026-02-20T15:03:45.846822+00:00","retracted":false,"artifacts":[{"path":"repro/rca_report.md","filename":"rca_report.md","size":4223,"category":"analysis"},{"path":"repro/reproduction_steps.sh","filename":"reproduction_steps.sh","size":2148,"category":"reproduction_script"},{"path":"bundle/source.json","filename":"source.json","size":4035,"category":"other"},{"path":"bundle/ticket.json","filename":"ticket.json","size":6475,"category":"other"},{"path":"bundle/ticket.md","filename":"ticket.md","size":1808,"category":"ticket"},{"path":"repro/poc.mjs","filename":"poc.mjs","size":1012,"category":"other"},{"path":"logs/final_variant_test.log","filename":"final_variant_test.log","size":2945,"category":"log"},{"path":"logs/result.txt","filename":"result.txt","size":13,"category":"other"},{"path":"logs/run1.log","filename":"run1.log","size":460,"category":"log"},{"path":"logs/run2.log","filename":"run2.log","size":460,"category":"log"},{"path":"logs/variant_1_vuln.log","filename":"variant_1_vuln.log","size":54,"category":"log"},{"path":"logs/variant_result.txt","filename":"variant_result.txt","size":13,"category":"other"},{"path":"logs/variant_test.log","filename":"variant_test.log","size":861,"category":"log"}]}