{"record":{"id":"e44331b6b70f60cd","repo":"denoland/deno","slug":"windows-file-names-may-not-contain-or-end-with","errorCode":null,"errorMessage":"Windows file names may not contain `\"` or end with `\\`","messagePattern":"Windows file names may not contain `\"` or end with `\\\\`","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"runtime/subprocess_windows/src/process.rs","lineNumber":1487,"sourceCode":"// Copyright The Rust Project Contributors - MIT\nfn make_bat_command_line(\n  script: &[u16],\n  args: &[&OsStr],\n  force_quotes: bool,\n) -> io::Result<Vec<u16>> {\n  // Set the start of the command line to `cmd.exe /c \"`\n  // It is necessary to surround the command in an extra pair of quotes,\n  // hence the trailing quote here. It will be closed after all arguments\n  // have been added.\n  // Using /e:ON enables \"command extensions\" which is essential for the `%` hack to work.\n  let mut cmd: Vec<u16> = \"/e:ON /v:OFF /d /c \\\"\".encode_utf16().collect();\n\n  // Push the script name surrounded by its quote pair.\n  cmd.push(b'\"' as u16);\n  // Windows file names cannot contain a `\"` character or end with `\\\\`.\n  // If the script name does then return an error.\n  if script.contains(&(b'\"' as u16)) || script.last() == Some(&(b'\\\\' as u16)) {\n    return Err(std::io::Error::new(\n      io::ErrorKind::InvalidInput,\n      \"Windows file names may not contain `\\\"` or end with `\\\\`\",\n    ));\n  }\n  cmd.extend_from_slice(script.strip_suffix(&[0]).unwrap_or(script));\n  cmd.push(b'\"' as u16);\n\n  // Append the arguments.\n  // FIXME: This needs tests to ensure that the arguments are properly\n  // reconstructed by the batch script by default.\n  for arg in args.iter().skip(1) {\n    cmd.push(' ' as u16);\n    let arg_bytes = arg.as_encoded_bytes();\n    // Disallow \\r and \\n as they may truncate the arguments.\n    const DISALLOWED: &[u8] = b\"\\r\\n\";\n    if arg_bytes.iter().any(|c| DISALLOWED.contains(c)) {\n      return Err(std::io::Error::new(\n        io::ErrorKind::InvalidInput,","sourceCodeStart":1469,"sourceCodeEnd":1505,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/runtime/subprocess_windows/src/process.rs#L1469-L1505","documentation":"Batch files (.bat/.cmd) are launched by wrapping the entire command line in an extra quoted cmd.exe /c \"...\" sequence. A script path containing a double quote would break out of that quoting, and one ending with a backslash would escape the closing quote, so both are rejected with InvalidInput before the command line is assembled.","triggerScenarios":"Spawning a .bat/.cmd file whose resolved path contains a \" character or ends with a backslash - e.g. new Deno.Command(\"C:\\\\tools\\\\setup.cmd\\\\\") or a path built from unvalidated user input that includes a quote.","commonSituations":"Paths assembled by string concatenation that keep a trailing separator; filenames containing quotes (extracted from archives or user input); config-driven script paths that were never validated before spawn.","solutions":["Build paths with a join helper instead of concatenation so no trailing backslash remains","Reject or strip double quotes in batch script paths before spawning","Rename the offending file - Windows itself forbids quotes in filenames, so such a path almost always indicates an upstream bug"],"exampleFix":"// before - path ends with a backslash before quoting is applied\nconst c = new Deno.Command(`C:\\\\tools\\\\${name}.cmd\\\\`);\n\n// after\nimport { join } from \"jsr:@std/path\";\nconst c = new Deno.Command(join(\"C:/tools\", `${name}.cmd`));","handlingStrategy":"validation","validationCode":"const isSafeWindowsScriptPath = (p: string) =>\n  !p.includes('\"') && !p.endsWith(\"\\\\\");\nif (/\\.(bat|cmd)$/i.test(prog) && !isSafeWindowsScriptPath(prog)) {\n  throw new Error(`unsafe batch script path: ${prog}`);\n}","typeGuard":"const isSafeScriptPath = (p: string): p is string =>\n  !p.includes('\"') && !p.endsWith(\"\\\\\");","tryCatchPattern":null,"preventionTips":["Build Windows paths with a join helper, never raw concatenation","Reject quote characters in any path that reaches spawn","Validate config-driven script paths at load time, not at spawn time"],"tags":["windows","subprocess","batch-file","path-quoting","invalid-input"],"backgroundTag":"invalid-filename-characters","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}