astrid-runtime/astrid · error

mountpoint contains traversal: {}

Error message

mountpoint contains traversal: {}

What it means

validate_mountpoint_layout detects ParentDir (..) or CurDir (.) components in the mountpoint and bails with the full offending path. Traversal components make the effective mount target depend on the process working directory and can be abused to redirect the mount outside the intended directory, so they are rejected outright.

Source

Thrown at crates/astrid-storage-provider-fskit/src/main.rs:535

}

#[cfg(not(unix))]
fn validate_mountpoint_ancestors(mountpoint: &Path) -> Result<()> {
    let _ = mountpoint;
    Ok(())
}

fn validate_mountpoint_layout(mountpoint: &Path) -> Result<()> {
    if !mountpoint.is_absolute() {
        bail!("mountpoint must be absolute");
    }
    if mountpoint.components().any(|component| {
        matches!(
            component,
            std::path::Component::ParentDir | std::path::Component::CurDir
        )
    }) {
        bail!("mountpoint contains traversal: {}", mountpoint.display());
    }
    if mountpoint.parent().is_none() {
        bail!("mountpoint must be below a parent directory");
    }
    Ok(())
}

#[cfg(target_os = "macos")]
pub(crate) async fn native_mount(lease: &StorageMountLeaseV1, mountpoint: &Path) -> Result<()> {
    let output = tokio::process::Command::new("/sbin/mount")
        .arg("-t")
        .arg("astridfs")
        .arg(&lease.resource_path)
        .arg(mountpoint)
        .output()
        .await
        .context("invoke macOS FSKit mount")?;
    if !output.status.success() {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Remove ".." and "." components; express the mountpoint as a clean absolute path
  2. Canonicalize the path before passing it: std::fs::canonicalize (existing path) or lexical normalization
  3. Validate/reject the user input upstream before constructing the mountpoint

Example fix

// before
let mountpoint = PathBuf::from("/Volumes/./fskit/../fskit-mnt");
// after
let mountpoint = PathBuf::from("/Volumes/fskit-mnt");
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_no_traversal(mp: &std::path::Path) -> anyhow::Result<()> {
    let bad = mp.components().any(|c| matches!(c, std::path::Component::ParentDir | std::path::Component::CurDir));
    anyhow::ensure!(!bad, "mountpoint contains traversal: {}", mp.display());
    Ok(())
}

Type guard

fn is_clean_path(p: &std::path::Path) -> bool {
    !p.components().any(|c| matches!(c, std::path::Component::ParentDir | std::path::Component::CurDir))
}

Prevention

When it happens

Trigger: Passing paths like /Volumes/../etc/mnt or ./mnt/fs to mount/unmount or any of the validate_* entry points.

Common situations: Concatenating strings instead of using PathBuf; user-supplied mount names containing ".."; normalizing with naive string joins rather than Path APIs.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/250df79abb865d7b. Report an issue: GitHub.