{"record":{"id":"96bd5de6e8d240ce","repo":"astrid-runtime/astrid","slug":"mountpoint-ancestor-is-writable-without-sticky-pro","errorCode":null,"errorMessage":"mountpoint ancestor is writable without sticky protection: {}","messagePattern":"mountpoint ancestor is writable without sticky protection: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-storage-provider-fskit/src/main.rs","lineNumber":509,"sourceCode":"        bail!(\n            \"macOS did not activate an astridfs mount at {}\",\n            mountpoint.display()\n        );\n    }\n    Ok(())\n}\n\n#[cfg(unix)]\nfn validate_mountpoint_ancestors(mountpoint: &Path) -> Result<()> {\n    use std::os::unix::fs::MetadataExt as _;\n\n    let mut ancestor = mountpoint.parent();\n    while let Some(path) = ancestor {\n        let metadata = std::fs::symlink_metadata(path)\n            .with_context(|| format!(\"inspect mountpoint ancestor {}\", path.display()))?;\n        let mode = metadata.mode();\n        if mode & 0o022 != 0 && mode & 0o1000 == 0 {\n            bail!(\n                \"mountpoint ancestor is writable without sticky protection: {}\",\n                path.display()\n            );\n        }\n        ancestor = path.parent();\n    }\n    Ok(())\n}\n\n#[cfg(not(unix))]\nfn validate_mountpoint_ancestors(mountpoint: &Path) -> Result<()> {\n    let _ = mountpoint;\n    Ok(())\n}\n\nfn validate_mountpoint_layout(mountpoint: &Path) -> Result<()> {\n    if !mountpoint.is_absolute() {\n        bail!(\"mountpoint must be absolute\");","sourceCodeStart":491,"sourceCodeEnd":527,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage-provider-fskit/src/main.rs#L491-L527","documentation":"This error is raised by validate_mountpoint_ancestors when walking up every ancestor directory of a mountpoint and finding a directory that is group/other-writable (mode & 0o022 != 0) without the sticky bit set (mode & 0o1000 == 0). Such a directory lets any local user swap or replace the mountpoint path, enabling a symlink/mount-target attack, so the FSKit provider refuses to mount or unmount through it. It is a local-security hardening check, not a functional failure.","triggerScenarios":"Calling mount/unmount (directly or via prepare_mountpoint, validate_mounted_mountpoint, validate_unmounted_mountpoint) when any parent directory of the mountpoint — e.g. /tmp/mnt with mode 0777 — is writable by non-owner and lacks the sticky bit.","commonSituations":"Mounting under a world-writable scratch directory such as /tmp/mymount where the user created a non-sticky subdirectory; CI containers where /var/mnt was created with 0777; reusing a shared build-artifact directory as a mount parent.","solutions":["Move the mountpoint under a root-owned, non-world-writable directory such as /Volumes or /mnt","Set the sticky bit on the ancestor: chmod +t /path/to/ancestor","Tighten the ancestor permissions: chmod o-w,g-w /path/to/ancestor","Verify with ls -ld each ancestor of the mountpoint until none are world-writable without +t"],"exampleFix":"// before (ancestor /srv/scratch is 0777)\nmountpoint = /srv/scratch/fs/mnt\n// after\nsudo chmod 0755 /srv/scratch  # or chmod +t /srv/scratch\nmountpoint = /srv/scratch/fs/mnt","handlingStrategy":"validation","validationCode":"fn mountpoint_ancestors_are_safe(mp: &std::path::Path) -> std::io::Result<()> {\n    let mut ancestor = mp.parent();\n    while let Some(path) = ancestor {\n        let mode = std::fs::symlink_metadata(path)?.mode();\n        if mode & 0o022 != 0 && mode & 0o1000 == 0 {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::PermissionDenied,\n                format!(\"{} writable without sticky\", path.display()),\n            ));\n        }\n        ancestor = path.parent();\n    }\n    Ok(())\n}","typeGuard":"fn is_protected_dir(md: &std::fs::Metadata) -> bool {\n    let mode = md.mode();\n    mode & 0o022 == 0 || mode & 0o1000 != 0\n}","tryCatchPattern":null,"preventionTips":["Mount only under root-owned directories like /Volumes or /mnt","Run chmod +t on shared scratch parents used for mounts","Audit ancestor permissions (ls -ld) in deployment scripts before mounting","Never create mount parents with 0777"],"tags":["security","filesystem","permissions","mount"],"backgroundTag":"insufficient-permissions","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"}