{"record":{"id":"edd23cf1d05f8452","repo":"astrid-runtime/astrid","slug":"named-pipe-endpoint-path-must-not-contain-a-parent","errorCode":null,"errorMessage":"named-pipe endpoint path must not contain a parent component","messagePattern":"named-pipe endpoint path must not contain a parent component","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/local_transport/windows.rs","lineNumber":576,"sourceCode":"    options\n        .first_pipe_instance(first)\n        .reject_remote_clients(true);\n\n    // SAFETY: `security.attributes` and its LocalAlloc-owned descriptor remain\n    // valid for the complete CreateNamedPipeW call. Tokio does not retain the\n    // pointer after `create_with_security_attributes_raw` returns.\n    unsafe {\n        options\n            .create_with_security_attributes_raw(pipe_name, (&raw mut security.attributes).cast())\n    }\n}\n\nfn pipe_name(path: &Path) -> io::Result<OsString> {\n    if path\n        .components()\n        .any(|component| matches!(component, std::path::Component::ParentDir))\n    {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidInput,\n            \"named-pipe endpoint path must not contain a parent component\",\n        ));\n    }\n    let absolute = std::path::absolute(path)?;\n    let sid = current_user_sid()?;\n    let endpoint = blake3::hash(absolute.as_os_str().as_encoded_bytes());\n    let digest = blake3::hash(sid.as_bytes());\n    Ok(OsString::from(format!(\n        \"{PIPE_PREFIX}{}{}\",\n        &digest.to_hex()[..24],\n        &endpoint.to_hex()[..40]\n    )))\n}\n\n#[cfg(feature = \"test-support\")]\npub(super) fn endpoint_name_for_test(path: &Path) -> io::Result<OsString> {\n    pipe_name(path)","sourceCodeStart":558,"sourceCodeEnd":594,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/local_transport/windows.rs#L558-L594","documentation":"pipe_name converts a user-supplied endpoint path into a per-user kernel pipe name (\\\\.\\pipe\\...). A `..` component would let the resulting pipe name escape the intended per-user namespace, so the library rejects any path containing a ParentDir component with InvalidInput before absolutizing it.","triggerScenarios":"Passing a path with `..` segments to connect(), bind(), or the test helpers — e.g. bind(\"/tmp/astrid/../service.sock\") or a config value assembled by string concatenation with `..`.","commonSituations":"Endpoint paths built by joining user input or env vars without normalization; configs ported from Unix socket setups with relative paths; typos like \"..\\pipe\" in settings files.","solutions":["Normalize the path before passing it: use std::path::absolute() (or Path::components-based cleanup) so no ParentDir component remains.","Build endpoint paths from a fixed base with PathBuf::join on simple names only.","Reject or canonicalize user/config-supplied endpoint paths at config-load time."],"exampleFix":"// before\nlet ep = Path::new(&format!(\"{}\\\\..\\\\svc\", base));\ntransport.bind(ep)?;\n// after\nlet ep = std::path::absolute(Path::new(&base))?.join(\"svc\");\ntransport.bind(&ep)?;","handlingStrategy":"validation","validationCode":"fn endpoint_path_ok(p: &Path) -> bool {\n    !p.components().any(|c| matches!(c, std::path::Component::ParentDir))\n}\n// call before bind/connect:\nassert!(endpoint_path_ok(&cfg.endpoint));","typeGuard":"fn safe_endpoint(p: &Path) -> Option<PathBuf> {\n    if p.components().any(|c| matches!(c, std::path::Component::ParentDir)) {\n        None\n    } else {\n        std::path::absolute(p).ok()\n    }\n}","tryCatchPattern":"match transport.bind(&path) {\n    Err(e) if e.kind() == io::ErrorKind::InvalidInput\n        && e.to_string().contains(\"parent component\") => {\n        eprintln!(\"endpoint {:?} contains '..'; fix config\", path);\n    }\n    other => other?,\n}","preventionTips":["Normalize endpoint paths with std::path::absolute before use.","Never interpolate raw user input into endpoint paths.","Validate endpoint paths once at config load, not at connect time."],"tags":["windows","named-pipes","path-validation","security","path-traversal"],"backgroundTag":"path-traversal-blocked","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}