{"record":{"id":"8a93f132ccdd1993","repo":"astrid-runtime/astrid","slug":"provider-name-returned-a-relative-or-traversing","errorCode":null,"errorMessage":"{provider_name} returned a relative or traversing native mountpoint: {}","messagePattern":"(.+?) returned a relative or traversing native mountpoint: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/storage.rs","lineNumber":276,"sourceCode":"    match &response.outcome {\n        StorageProviderOutcomeV1::Success(\n            StorageProviderSuccessV1::Mounted { mountpoint, .. }\n            | StorageProviderSuccessV1::Status { mountpoint, .. },\n        ) => validate_response_mountpoint(provider_name, mountpoint),\n        _ => Ok(()),\n    }\n}\n\nfn validate_response_mountpoint(provider_name: &str, mountpoint: &Path) -> Result<()> {\n    if !mountpoint.is_absolute()\n        || mountpoint.components().any(|component| {\n            matches!(\n                component,\n                std::path::Component::ParentDir | std::path::Component::CurDir\n            )\n        })\n    {\n        bail!(\n            \"{provider_name} returned a relative or traversing native mountpoint: {}\",\n            mountpoint.display()\n        );\n    }\n    Ok(())\n}\n\nfn capabilities_are_unique(capabilities: &[StorageProviderCapabilityV1]) -> bool {\n    let mut admitted = Vec::with_capacity(capabilities.len());\n    for capability in capabilities {\n        if admitted.contains(capability) {\n            return false;\n        }\n        admitted.push(*capability);\n    }\n    true\n}\n","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/storage.rs#L258-L294","documentation":"validate_response_mountpoint sanitizes mountpoint paths returned by native providers. The path must be absolute and must not contain ParentDir (..) or CurDir (.) components. Otherwise a malicious or buggy provider could point the CLI at an arbitrary or traversing filesystem location, so the CLI bails.","triggerScenarios":"A Mounted/Status success outcome carries a mountpoint that is relative, or contains '..'/'.' path components — checked via std::path::Component inspection in validate_response_mountpoint, called from validate_response.","commonSituations":"Provider returns a relative path because it resolved the mountpoint against its own CWD; a compromised provider attempts a path-traversal to place a mount outside allowed roots; a provider on a different OS returns a path with components the CLI doesn't accept.","solutions":["Fix the provider to return a canonical, absolute mountpoint path (e.g. via fs::canonicalize before responding)","Ensure the provider's CWD doesn't influence mountpoint resolution","If you control the mount location, mount under a fixed absolute root directory","Report the provider as misbehaving/compromised if traversal appears intentional"],"exampleFix":"// before (provider)\nmountpoint: PathBuf::from(\"../mnt/astrid\"),\n// after\nmountpoint: std::fs::canonicalize(\"/mnt/astrid\")?,","handlingStrategy":"validation","validationCode":"fn mountpoint_safe(p: &std::path::Path) -> bool { p.is_absolute() && !p.components().any(|c| matches!(c, std::path::Component::ParentDir | std::path::Component::CurDir)) }","typeGuard":"fn trusted_mountpoint(p: &Path) -> Option<&Path> { if mountpoint_safe(p) { Some(p) } else { None } }","tryCatchPattern":"if !mountpoint_safe(&mountpoint) {\n    eprintln!(\"refusing unsafe mountpoint from provider: {}\", mountpoint.display());\n    return Ok(ExitCode::FAILURE);\n}","preventionTips":["Canonicalize mountpoints in the provider before responding","Mount only under fixed absolute roots","Treat provider-supplied paths as untrusted input and re-validate"],"tags":["path-traversal","security","native-provider"],"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-17T15:17:12.973Z"}