openai/codex · critical
failed to convert argv to CString: {err}
Error message
failed to convert argv to CString: {err} What it means
Before exec'ing bwrap, argv_to_cstrings converts every argument to a C string. Rust Strings may contain interior NUL bytes, but C argv entries cannot, so CString::new fails on an argument holding a NUL byte and the helper panics with the NulError, which reports the offending byte position.
Source
Thrown at codex-rs/linux-sandbox/src/exec_util.rs:10
use std::ffi::CString;
use std::fs::File;
use std::os::fd::AsRawFd;
pub(crate) fn argv_to_cstrings(argv: &[String]) -> Vec<CString> {
let mut cstrings: Vec<CString> = Vec::with_capacity(argv.len());
for arg in argv {
match CString::new(arg.as_str()) {
Ok(value) => cstrings.push(value),
Err(err) => panic!("failed to convert argv to CString: {err}"),
}
}
cstrings
}
pub(crate) fn make_files_inheritable(files: &[File]) {
for file in files {
clear_cloexec(file.as_raw_fd());
}
}
fn clear_cloexec(fd: libc::c_int) {
// SAFETY: `fd` is an owned descriptor kept alive by `files`.
let flags = unsafe { libc::fcntl(fd, libc::F_GETFD) };
if flags < 0 {
let err = std::io::Error::last_os_error();
panic!("failed to read fd flags for preserved bubblewrap file descriptor {fd}: {err}");
}View on GitHub (pinned to 339751715c)
Solutions
- Locate the offending argument using the NUL position in the panic message and sanitize the data at its source.
- Reject or strip NUL bytes in user input before constructing the command line.
- If the data was NUL-separated by design, split it into separate arguments instead of one embedded-NUL string.
Example fix
// before
let argv = vec![program, user_input]; // user_input with a NUL byte panics in argv_to_cstrings
// after: validate before the sandbox call
for (i, arg) in argv.iter().enumerate() {
if arg.contains('\u{0}') {
return Err(format!("argument {i} contains a NUL byte"));
}
} Defensive patterns
Strategy: validation
Validate before calling
fn args_are_cstring_safe(argv: &[String]) -> Result<(), usize> {
argv.iter().position(|a| a.contains('\u{0}')).map_or(Ok(()), Err)
}
args_are_cstring_safe(&argv)?; Type guard
fn is_cstring_safe(s: &str) -> bool { !s.contains('\u{0}') } Prevention
- Validate command strings and filenames for NUL bytes at the trust boundary where user input enters.
- Never build argv by concatenating NUL-separated buffers; split first.
- The panic message includes the offending byte position; use it to pinpoint the bad argument.
When it happens
Trigger: Passing any argument to the sandboxed command that contains a NUL byte: a filename, env value, or flag built from unvalidated input; a marshalling bug that converts length-prefixed or NUL-separated buffers into one String; binary data leaking into argv.
Common situations: User-supplied filenames or commands containing NUL; IPC layers that join NUL-separated fields instead of splitting them; unchecked UTF-8 conversions of OS strings; fuzzing.
Related errors
- invalid bundled bubblewrap fd path: {err}
- invalid legacy bubblewrap fd mount: {error}
- plugin cache root should be absolute: {err}
- only user input can be added to the user-message queue
- queued user input exceeds the maximum length of {MAX_USER_IN
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/3c33edca59394f1f.
Report an issue: GitHub.