{"record":{"id":"c1976b0cbfc2b71a","repo":"denoland/deno","slug":"nul-byte-found-in-provided-data-c1976b","errorCode":null,"errorMessage":"nul byte found in provided data","messagePattern":"nul byte found in provided data","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"runtime/subprocess_windows/src/process.rs","lineNumber":1601,"sourceCode":"        ]);\n      }\n      backslashes = 0;\n    }\n    cmd.push(x);\n  }\n  if quote {\n    // Add n backslashes to total 2n before ending `\"`.\n    cmd.extend((0..backslashes).map(|_| '\\\\' as u16));\n    cmd.push('\"' as u16);\n  }\n  Ok(())\n}\n\n// lifted from https://github.com/rust-lang/rust/blob/bc1d7273dfbc6f8a11c0086fa35f6748a13e8d3c/library/std/src/sys/pal/windows/mod.rs#L289\n// Copyright The Rust Project Contributors - MIT\nfn ensure_no_nuls<T: AsRef<OsStr>>(s: T) -> crate::io::Result<T> {\n  if s.as_ref().encode_wide().any(|b| b == 0) {\n    Err(std::io::Error::new(\n      io::ErrorKind::InvalidInput,\n      \"nul byte found in provided data\",\n    ))\n  } else {\n    Ok(s)\n  }\n}\n\nfn command_prompt() -> io::Result<WCString> {\n  let mut buffer =\n    vec![0u16; windows_sys::Win32::Foundation::MAX_PATH as usize];\n  let len =\n    unsafe { GetSystemDirectoryW(buffer.as_mut_ptr(), buffer.len() as u32) };\n  if len == 0 {\n    return Err(io::Error::last_os_error());\n  }\n  buffer.truncate(len as usize);\n  buffer.extend(\"\\\\cmd.exe\".encode_utf16().chain([0]));","sourceCodeStart":1583,"sourceCodeEnd":1619,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/runtime/subprocess_windows/src/process.rs#L1583-L1619","documentation":"The Windows command line - the executable path and every argument - is encoded as NUL-terminated UTF-16, so process.rs applies the same guard as the environment path: ensure_no_nuls() rejects any program path or argument containing U+0000 with InvalidInput, because an embedded NUL would truncate the command line handed to CreateProcessW.","triggerScenarios":"new Deno.Command(prog, { args: [...] }).spawn() on Windows where prog or any argument contains a NUL character, e.g. args: [\"a\\u0000b\"], or a file path built from a buffer with embedded NUL terminators.","commonSituations":"Strings decoded from binary formats or length-prefixed buffers; filenames taken from device listings or network protocols that embed NULs; JSON payloads containing \\u0000 escapes passed through to spawn.","solutions":["Strip U+0000 from the program path and all arguments before spawn","Pass binary payloads via stdin or a temp file rather than argv","Validate at the trust boundary: reject NUL-containing input as soon as it enters your app"],"exampleFix":"// before\nconst c = new Deno.Command(\"tool\", { args: [chunk.toString()] }); // chunk has NULs\n\n// after\nconst arg = chunk.toString().replaceAll(\"\\u0000\", \"\");\nconst c = new Deno.Command(\"tool\", { args: [arg] });","handlingStrategy":"validation","validationCode":"const hasNul = (s: string) => s.includes(\"\\u0000\");\nconst safeArgs = args.map(String).map((a) => {\n  if (hasNul(a)) throw new Error(\"argument contains NUL byte\");\n  return a;\n});","typeGuard":"const isNulFree = (s: string): s is string => !s.includes(\"\\u0000\");","tryCatchPattern":"try {\n  const child = new Deno.Command(prog, { args }).spawn();\n} catch (err) {\n  if (err instanceof TypeError && err.message.includes(\"nul byte\")) {\n    // strip U+0000 from prog/args and retry\n  } else throw err;\n}","preventionTips":["Validate decoded strings from binary formats before they reach spawn","Pass binary payloads via stdin or files, not argv","Reject NUL-containing input at the API boundary of your app"],"tags":["windows","subprocess","nul-byte","command-arguments"],"backgroundTag":"nul-byte-in-string","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"}