{"record":{"id":"afa95fabf02a822c","repo":"denoland/deno","slug":"env-contains-nul","errorCode":null,"errorMessage":"env contains NUL","messagePattern":"env contains NUL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/tools/desktop.rs","lineNumber":5764,"sourceCode":"      match v {\n        Some(v) => {\n          env_map.insert(k.to_os_string(), v.to_os_string());\n        }\n        None => {\n          env_map.remove(k);\n        }\n      }\n    }\n    let envp: Vec<CString> = env_map\n      .into_iter()\n      .map(|(k, v)| {\n        let mut s =\n          Vec::with_capacity(k.as_bytes().len() + 1 + v.as_bytes().len());\n        s.extend_from_slice(k.as_bytes());\n        s.push(b'=');\n        s.extend_from_slice(v.as_bytes());\n        CString::new(s).map_err(|_| {\n          std::io::Error::new(\n            std::io::ErrorKind::InvalidInput,\n            \"env contains NUL\",\n          )\n        })\n      })\n      .collect::<std::io::Result<_>>()?;\n    let cwd = match cmd.get_current_dir() {\n      Some(p) => {\n        Some(CString::new(p.as_os_str().as_bytes()).map_err(|_| {\n          std::io::Error::new(std::io::ErrorKind::InvalidInput, \"cwd has NUL\")\n        })?)\n      }\n      None => None,\n    };\n    Ok((program, argv, envp, cwd))\n  }\n\n  pub fn spawn(cmd: &std::process::Command) -> std::io::Result<Child> {","sourceCodeStart":5746,"sourceCodeEnd":5782,"githubUrl":"https://github.com/denoland/deno/blob/f7822238cab635a3a19f99f493f675fa81a7f9d8/cli/tools/desktop.rs#L5746-L5782","documentation":"While building the envp array for posix_spawn, `flatten()` joins each inherited or overridden environment key and value into a single `KEY=value` C string. If either side contains a NUL byte, `CString::new` fails and the whole spawn is rejected with `io::ErrorKind::InvalidInput` (\"env contains NUL\").","triggerScenarios":"`Command::env(k, v)` (or the inherited process environment) carrying a key or value with an embedded 0x00 — e.g. tokens decoded from binary formats, base64-mangled secrets, or `env::vars_os` from a parent process with malformed environ entries.","commonSituations":"Passing machine-generated credentials/tokens as env vars; containers whose environ was written by a buggy injector; debug builds that stuff packed structs into env values.","solutions":["Validate both key and value with a NUL check in `Command::env` calls and when inheriting unusual env.","Fix the producer writing 0x00 into the environ entry; encode binary values (hex/base64) instead of raw bytes.","Clear or replace the offending variable before spawning if it is not needed by the child."],"exampleFix":"// before\nfor (k, v) in &extra_env { cmd.env(k, v); }\n\n// after\nfn reject_nul(bytes: &[u8], what: &str) -> std::io::Result<()> {\n  if bytes.contains(&0) {\n    return Err(std::io::Error::new(\n      std::io::ErrorKind::InvalidInput,\n      format!(\"{what} contains NUL\"),\n    ));\n  }\n  Ok(())\n}\nfor (k, v) in &extra_env {\n  reject_nul(k.as_bytes(), \"env key\")?;\n  reject_nul(v.as_bytes(), \"env value\")?;\n  cmd.env(k, v);\n}","handlingStrategy":"validation","validationCode":"fn reject_nul(bytes: &[u8], what: &str) -> std::io::Result<()> {\n  if bytes.contains(&0) {\n    return Err(std::io::Error::new(\n      std::io::ErrorKind::InvalidInput,\n      format!(\"{what} contains NUL\"),\n    ));\n  }\n  Ok(())\n}\nfor (k, v) in cmd.get_envs() {\n  reject_nul(k.as_bytes(), \"env key\")?;\n  if let Some(v) = v { reject_nul(v.as_bytes(), \"env value\")?; }\n}","typeGuard":"fn is_nul_free(s: &std::ffi::OsStr) -> bool {\n  !s.as_bytes().contains(&0)\n}","tryCatchPattern":"match spawn(cmd) {\n  Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => {\n    // scan env for the offending entry and drop/fix it before retrying\n  }\n  other => other,\n}","preventionTips":["Never pass raw binary secrets via env vars — encode them","Validate inherited environ when the parent environment is machine-generated","Drop unneeded variables with env_remove instead of forwarding everything"],"tags":["subprocess","posix-spawn","nul-byte","environment-variables","invalid-input"],"backgroundTag":"nul-byte-in-env-var","analyzedSha":"f7822238cab635a3a19f99f493f675fa81a7f9d8","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}