{"record":{"id":"926ddecee02e9728","repo":"GitoxideLabs/gitoxide","slug":"git-daemon-repository-paths-must-not-contain-nul-o","errorCode":null,"errorMessage":"git daemon repository paths must not contain NUL or LF","messagePattern":"git daemon repository paths must not contain NUL or LF","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-transport/src/client/git/mod.rs","lineNumber":38,"sourceCode":"    pub(in crate::client) mode: ConnectMode,\n}\n\nmod message {\n    use bstr::{BString, ByteVec};\n\n    use crate::{Protocol, Service};\n\n    pub fn connect(\n        service: Service,\n        desired_version: Protocol,\n        path: &[u8],\n        virtual_host: Option<&(String, Option<u16>)>,\n        extra_parameters: &[(&str, Option<&str>)],\n    ) -> std::io::Result<BString> {\n        let path = gix_url::expand_path::for_shell(path.into());\n        let is_forbidden = |byte| matches!(byte, b'\\0' | b'\\n');\n        if path.iter().copied().any(is_forbidden) {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::InvalidInput,\n                \"git daemon repository paths must not contain NUL or LF\",\n            ));\n        }\n        if virtual_host.is_some_and(|(host, _)| host.bytes().any(is_forbidden)) {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::InvalidInput,\n                \"git daemon virtual hosts must not contain NUL or LF\",\n            ));\n        }\n\n        let mut out = bstr::BString::from(service.as_str());\n        out.push(b' ');\n        out.extend_from_slice(&path);\n        out.push(0);\n        if let Some((host, port)) = virtual_host {\n            out.push_str(\"host=\");\n            out.extend_from_slice(host.as_bytes());","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-transport/src/client/git/mod.rs#L20-L56","documentation":"The `git://` (git daemon) transport rejects repository paths containing NUL (`\\0`) or LF (`\\n`) bytes before building the request, because these bytes are forbidden in the daemon protocol's path argument. The connection is refused locally with `InvalidInput` before any network I/O.","triggerScenarios":"Calling `gix::connect()` (or the git client's `request()`/`connect`) with a `git://` URL whose expanded path contains NUL or newline bytes.","commonSituations":"URLs built by concatenation that accidentally embed a trailing newline (e.g. from a file or env var read without trimming); binary garbage in programmatically constructed URLs.","solutions":["Trim whitespace/newlines from the URL/path string before connecting","Reject or sanitize path components containing NUL/LF before constructing the `git://` URL","Log/validate the URL at the application boundary"],"exampleFix":"// before\nlet url = format!(\"git://host{}\n\"); // trailing LF from input\n// after\nlet url = format!(\"git://host{}\").trim().to_string();","handlingStrategy":"validation","validationCode":"fn validate_git_daemon_path(path: &str) -> Result<(), String> {\n    if path.bytes().any(|b| b == b'\\0' || b == b'\\n') {\n        Err(\"git:// path contains NUL or LF\".into())\n    } else { Ok(()) }\n}","typeGuard":null,"tryCatchPattern":"match gix::connect(url, gix::protocol::transport::Protocol::Git) {\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => {\n        eprintln!(\"sanitize the git:// URL: {e}\");\n    }\n    other => other?,\n}","preventionTips":["Trim and sanitize URLs read from files/env/config before connecting","Reject control characters at the URL-parsing boundary","Log the raw URL bytes when constructing git:// connections"],"tags":["git","protocol","url-validation","input-validation"],"backgroundTag":"invalid-url-format","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}