{"record":{"id":"20291ab69d0260e9","repo":"abhigyanpatwari/GitNexus","slug":"argument-contains-a-double-quote-unsafe-for-the-w","errorCode":null,"errorMessage":"argument contains a double quote, unsafe for the Windows shell: ${JSON.stringify(arg)}","messagePattern":"argument contains a double quote, unsafe for the Windows shell: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/embeddings/runtime-install.ts","lineNumber":313,"sourceCode":" * Rules (validated against Node source, MS cmd/CRT docs, BatBadBut, Rust std):\n * reject NUL/CR/LF and embedded `\"` (both unrepresentable/unsafe at the cmd\n * layer, and `\"` is illegal in Windows paths and npm specs); wrap in double\n * quotes when empty or containing whitespace/metacharacters; double the trailing\n * backslash run so the added closing quote is not itself escaped (`C:\\` →\n * `\"C:\\\\\"`). `^` is literal inside cmd double quotes across all three parse\n * layers (cmd `/c` → npm.cmd's `%*` re-parse → node CRT argv). Two documented\n * ceilings quoting can't close: a defined `%VAR%` expands once at the first cmd\n * parse, and `!` expands only under registry-enabled delayed expansion — both\n * are the env-var owner's trust, out of the malicious-repo threat model.\n */\nexport const quoteWin32Arg = (arg: string): string => {\n  if (/[\\0\\r\\n]/.test(arg)) {\n    throw new Error(\n      `argument contains NUL/CR/LF, unsafe for the Windows shell: ${JSON.stringify(arg)}`,\n    );\n  }\n  if (arg.includes('\"')) {\n    throw new Error(\n      `argument contains a double quote, unsafe for the Windows shell: ${JSON.stringify(arg)}`,\n    );\n  }\n  if (arg !== '' && !WIN32_NEEDS_QUOTING.test(arg)) return arg;\n  const trailingBackslashes = /\\\\*$/.exec(arg)?.[0].length ?? 0;\n  return `\"${arg}${'\\\\'.repeat(trailingBackslashes)}\"`;\n};\n\n/**\n * Compose a full `cmd.exe` command line: the command stays unquoted (so\n * PATH/PATHEXT resolves a bare name or `.cmd` shim), args are individually\n * quoted. Passing this as spawn's first (only) string argument — no args array\n * — yields a byte-identical `cmd.exe /d /s /c \"…\"` line while avoiding DEP0190\n * (the runtime deprecation warning Node >=24 emits for\n * `spawn(file, args, {shell:true})`). Exported generically so the real-cmd.exe\n * round-trip test drives the exact same composition the npm spawn uses.\n */\nexport const composeWin32Command = (command: string, args: string[]): string =>","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/core/embeddings/runtime-install.ts#L295-L331","documentation":"Thrown by quoteWin32Arg() when a Windows command-line argument contains a double quote character. A literal \" cannot be escaped reliably across the cmd.exe /c, npm.cmd %* re-parse, and node CRT argv layers, and it is additionally illegal in Windows paths and npm specs, so the helper rejects it instead of quoting. This is an injection/lint guard on arguments destined for a cmd.exe command line.","triggerScenarios":"Calling quoteWin32Arg(arg) where arg includes \\\" — e.g. a package spec like pkg@\\\"1.0.0\\\", a path with a stray quote from templating/string concatenation, or untrusted input pasted into a config value that later becomes an install argument on Windows.","commonSituations":"Building npm install arguments from user-supplied version strings; shell snippets copied from documentation that include quotes; values produced by string interpolation of JSON-encoded strings. Only bites on Windows, where the cmd.exe code path is used.","solutions":["Remove or reject the double quote in the value before composing the command: if (arg.includes('\"')) throw ... or strip/percent-encode as appropriate for the consumer.","Fix the producer of the value — usually a JSON.stringify'd string or a copy-pasted shell fragment leaking a literal \\\" into the spec.","Prefer spawn with an argument array and shell:false so no cmd.exe quoting round-trip is needed.","For Windows paths, note \\\" is not a legal path character at all: treat its presence as corrupt input, not something to encode."],"exampleFix":"// before\nconst spec = `onnxruntime-node@${userVersion}`; // userVersion = '\\\"1.19.0\\\"'\nconst cmdline = composeWin32Cmd('npm', ['install', spec]);\n// -> Error: argument contains a double quote, unsafe for the Windows shell\n\n// after\nif (!/^[\\w.\\-+^~<>=| ,:]*$/.test(userVersion)) throw new Error('invalid version spec');\nconst cmdline = composeWin32Cmd('npm', ['install', `onnxruntime-node@${userVersion}`]);","handlingStrategy":"validation","validationCode":"// Allow-list the characters that can appear in npm specs/paths you pass on Windows.\nexport function assertSafeWin32Arg(arg: string): void {\n  if (arg.includes('\"')) {\n    throw new Error(\n      `unsafe argument (double quote): ${JSON.stringify(arg)} — \" is illegal in Windows paths and npm specs`,\n    );\n  }\n}\n\nassertSafeWin32Arg(`onnxruntime-node@${version}`);","typeGuard":"export const isQuoteFreeArg = (arg: string): boolean => !arg.includes('\"');","tryCatchPattern":"try {\n  cmdline = composeWin32Cmd(npmBin, args);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('double quote')) {\n    // A quoted string leaked into the spec (e.g. JSON.stringify output) — strip and retry.\n    const clean = args.map((a) => a.replaceAll('\"', ''));\n    cmdline = composeWin32Cmd(npmBin, clean);\n  } else {\n    throw err;\n  }\n}","preventionTips":["Never feed JSON.stringify output or copied shell snippets directly into spawn arguments.","Validate version specs/package names against a character allow-list before building install commands.","Use spawn with an args array and shell:false wherever the child supports it; reserve cmd.exe composition for .cmd shims only.","Test the Windows code path in CI (wine or a windows runner) — these guards never fire on POSIX dev machines."],"tags":["windows","shell","security","injection","validation"],"backgroundTag":"shell-command-injection","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}