{"record":{"id":"c3ba11422d1dad24","repo":"wasmerio/wasmer","slug":"invalid-guest-mount-path-parent-traversal-es","errorCode":null,"errorMessage":"Invalid guest mount path \"{}\": parent traversal escapes the virtual root","messagePattern":"Invalid guest mount path \"(.+?)\": parent traversal escapes the virtual root","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/wasix/src/runners/wasi_common.rs","lineNumber":206,"sourceCode":"    vars.into_iter()\n        .map(|(name, value)| (name.into_encoded_bytes(), value.into_encoded_bytes()))\n}\n\nfn normalized_mount_path(guest_path: &str) -> Result<PathBuf, Error> {\n    let mut guest_path = PathBuf::from(guest_path);\n\n    if guest_path.is_relative() {\n        guest_path = apply_relative_path_mounting_hack(&guest_path);\n    }\n\n    let mut normalized = PathBuf::from(\"/\");\n    for component in guest_path.components() {\n        match component {\n            Component::RootDir => normalized = PathBuf::from(\"/\"),\n            Component::CurDir => {}\n            Component::ParentDir => {\n                if normalized.as_os_str() == \"/\" {\n                    anyhow::bail!(\n                        \"Invalid guest mount path \\\"{}\\\": parent traversal escapes the virtual root\",\n                        guest_path.display()\n                    );\n                }\n                normalized.pop();\n            }\n            Component::Normal(part) => normalized.push(part),\n            Component::Prefix(_) => {\n                anyhow::bail!(\n                    \"Invalid guest mount path \\\"{}\\\": platform-specific prefixes are not supported\",\n                    guest_path.display()\n                );\n            }\n        }\n    }\n\n    Ok(normalized)\n}","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/wasmerio/wasmer/blob/8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5/lib/wasix/src/runners/wasi_common.rs#L188-L224","documentation":"normalized_mount_path canonicalizes a guest mount path before wiring it into the WASI filesystem. When a '..' component would pop past the root of the virtual filesystem (i.e. the normalized path is already '/' and another ParentDir is seen), it refuses the mount because the path escapes the virtual root, which would be unsafe/ambiguous.","triggerScenarios":"Calling prepare_filesystem (or the runner setup) with a guest mount path containing leading or excess '..' components, e.g. '..' , '/../data', '/a/../..' — any path whose normalization underflows root.","commonSituations":"Configuration mistakes in mount maps (e.g. TOML/CLI --mapdir with '..' in the guest side); programmatically-built paths joined with user input containing '..'; Windows-style habits where relative parent paths were expected to resolve against a host cwd.","solutions":["Remove the leading/extra '..' components from the guest side of the mount spec so it stays within the virtual root","If you intended to mount a host parent directory, move the '..' to the HOST path portion of the mount mapping, keeping the guest path absolute and rooted (e.g. guest '/data' -> host '../data')","Normalize the path yourself before passing it in (e.g. path.clean() semantics) and assert it stays under '/'","If the input comes from user config, validate/reject it at config-load time with a clearer message"],"exampleFix":"// before\nrunner.with_mount(\"..\", \"/guest/data\")?;\n// after: keep the '..' on the host side, guest path rooted\nrunner.with_mount(\"/guest/data\", \"../host-data\")?;","handlingStrategy":"validation","validationCode":"fn validate_guest_mount_path(guest: &str) -> Result<(), String> {\n    use path_clean::PathClean;\n    let p = std::path::Path::new(guest);\n    if !guest.starts_with('/') {\n        return Err(format!(\"guest mount path must be absolute: {guest}\"));\n    }\n    let cleaned = p.clean(); // resolves '..' lexically\n    if cleaned.components().any(|c| matches!(c, std::path::Component::ParentDir)) {\n        return Err(format!(\"guest mount path escapes virtual root: {guest}\"));\n    }\n    Ok(())\n}\nvalidate_guest_mount_path(\"/data\")?;","typeGuard":"fn is_rooted_guest_path(p: &std::path::Path) -> bool {\n    use std::path::Component;\n    p.is_absolute()\n        && p.components()\n            .all(|c| !matches!(c, Component::ParentDir | Component::Prefix(_)))\n}","tryCatchPattern":null,"preventionTips":["Always author guest mount paths as absolute, rooted paths ('/x/y') in config","Never pass user-controlled paths directly into the guest slot without normalization","Keep '..' moves on the host side of the mapping only","Add a config-load-time lint that rejects non-canonical guest paths with a clear message"],"tags":["wasix","mount","path-validation","security","wasi"],"backgroundTag":"path-traversal-rejected","analyzedSha":"8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5","analyzedAt":"2026-09-01T23:06:31.009Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}