{"record":{"id":"966b9191b5e6c803","repo":"vercel-labs/agent-browser","slug":"nul-in-chrome-argument","errorCode":null,"errorMessage":"NUL in Chrome argument","messagePattern":"NUL in Chrome argument","errorType":"error_code","errorClass":"io::Error (InvalidInput)","httpStatus":null,"severity":"error","filePath":"cli/src/native/cdp/windows_process.rs","lineNumber":301,"sourceCode":"    // SAFETY: Duplicate into our process; ownership is transferred below.\n    check(unsafe {\n        DuplicateHandle(\n            GetCurrentProcess(),\n            handle,\n            GetCurrentProcess(),\n            &mut duplicate,\n            0,\n            1,\n            DUPLICATE_SAME_ACCESS,\n        )\n    })?;\n    owned(duplicate)\n}\n\nfn wide(value: &OsStr) -> io::Result<Vec<u16>> {\n    let mut value: Vec<_> = value.encode_wide().collect();\n    if value.contains(&0) {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidInput,\n            \"NUL in Chrome argument\",\n        ));\n    }\n    value.push(0);\n    Ok(value)\n}\n\n/// Quote a single argument for Chrome's Windows C runtime. Backslashes are\n/// doubled only before a quote or the closing quote, preserving paths/JSON.\nfn quoted(value: &OsStr) -> io::Result<Vec<u16>> {\n    let value = wide(value)?;\n    let mut output = vec![b'\"' as u16];\n    let mut slashes = 0;\n    for &ch in &value[..value.len() - 1] {\n        if ch == b'\\\\' as u16 {\n            slashes += 1;\n            continue;","sourceCodeStart":283,"sourceCodeEnd":319,"githubUrl":"https://github.com/vercel-labs/agent-browser/blob/921a57b64da9d75bf0bd43d84199e15cbfa6583a/cli/src/native/cdp/windows_process.rs#L283-L319","documentation":"The `wide` helper converts an OsStr (a Chrome argument such as an exe path, flag, or URL) to a NUL-terminated UTF-16 buffer for Windows APIs like CreateProcessW. Windows native string APIs cannot represent embedded NUL characters, so before appending the terminating NUL the function scans the encoded value for interior 0u16 code units and refuses the input with this error instead of silently truncating the argument. It is a fail-fast input validation guard for Windows process spawning.","triggerScenarios":"Calling spawn/quoted paths that pass an OsStr containing interior NUL bytes to `wide(...)`; i.e. any Chrome argument, executable path, working directory, or environment value built from data that contains a 0 byte (e.g. bytes from a file, network input, or a String constructed with '\\0' inside).","commonSituations":"Reading a Chrome path or argument list from a config file, database, or binary source that includes a trailing/interior NUL byte; interpolating untrusted user input into a Chrome flag; reconstructing a path from Windows wide-char data and accidentally keeping the terminator; concatenating byte buffers instead of strings.","solutions":["Trim or strip NUL bytes from the argument before passing it to the daemon/CLI, e.g. `s.trim_end_matches('\\0')` or filter out 0 bytes from the source data.","Validate every Chrome argument (path, flags, URL) for '\\0' before invoking the library and reject or sanitize at your config-loading boundary.","If the value comes from reading a file or byte buffer, decode it as UTF-8/UTF-16 properly instead of copying raw bytes that may include terminators."],"exampleFix":"// before\nlet exe = std::fs::read_to_string(\"chrome_path.txt\")?; // file saved as UTF-16, contains '\\0'\ndaemon.launch(&exe, &[\"--headless\"])?;\n\n// after\nlet exe = std::fs::read_to_string(\"chrome_path.txt\")?.trim_end_matches('\\0').to_string();\nassert!(!exe.contains('\\0'), \"chrome path must not contain NUL bytes\");\ndaemon.launch(&exe, &[\"--headless\"])?;","handlingStrategy":"validation","validationCode":"fn assert_no_nul(arg: &std::ffi::OsStr) -> std::io::Result<()> {\n    use std::os::windows::ffi::OsStrExt;\n    if arg.encode_wide().any(|c| c == 0) {\n        return Err(std::io::Error::new(\n            std::io::ErrorKind::InvalidInput,\n            \"NUL in Chrome argument\",\n        ));\n    }\n    Ok(())\n}\n// run for every arg before launching Chrome:\n// assert_no_nul(exe.as_ref())?; for flag in flags { assert_no_nul(flag.as_ref())?; }","typeGuard":"fn is_nul_free(arg: &std::ffi::OsStr) -> bool {\n    use std::os::windows::ffi::OsStrExt;\n    !arg.encode_wide().any(|c| c == 0)\n}","tryCatchPattern":null,"preventionTips":["Strip trailing and interior NUL bytes when loading paths or arguments from files, registries, or byte buffers.","Never build CLI arguments by concatenating raw byte buffers; always go through String/OsStr string APIs.","Sanitize untrusted/user-supplied input before it becomes a Chrome flag or executable path.","On Windows, remember OsStr::encode_wide output must not include terminators; the terminating NUL is appended by the spawn helper."],"tags":["windows","process-spawn","input-validation","encoding"],"backgroundTag":"null-argument","analyzedSha":"921a57b64da9d75bf0bd43d84199e15cbfa6583a","analyzedAt":"2026-09-10T02:57:29.894Z","contentChangedAt":"2026-09-10T02:57:29.894Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}