{"record":{"id":"e22441fae7cbe8d4","repo":"astrid-runtime/astrid","slug":"capsule-projection-escaped-its-root","errorCode":null,"errorMessage":"capsule projection escaped its root: {}","messagePattern":"capsule projection escaped its root: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/lib.rs","lineNumber":1630,"sourceCode":"        Ok(())\n    }\n\n    /// Inventory a projection without traversing redirects or special files.\n    #[cfg(not(all(target_arch = \"wasm32\", target_os = \"unknown\")))]\n    fn inventory_projection_files(root: &Path) -> anyhow::Result<ProjectionInventory> {\n        fn walk(\n            root: &Path,\n            directory: &Path,\n            inventory: &mut ProjectionInventory,\n        ) -> anyhow::Result<()> {\n            for entry in std::fs::read_dir(directory).map_err(|error| {\n                anyhow::anyhow!(\"read capsule projection {}: {error}\", directory.display())\n            })? {\n                let entry = entry\n                    .map_err(|error| anyhow::anyhow!(\"read capsule projection entry: {error}\"))?;\n                let path = entry.path();\n                let relative = path.strip_prefix(root).map_err(|_| {\n                    anyhow::anyhow!(\"capsule projection escaped its root: {}\", path.display())\n                })?;\n                let relative_text = relative.to_str().ok_or_else(|| {\n                    anyhow::anyhow!(\"capsule projection path is not UTF-8: {}\", path.display())\n                })?;\n                let metadata = std::fs::symlink_metadata(&path).map_err(|error| {\n                    anyhow::anyhow!(\"inspect capsule projection {}: {error}\", path.display())\n                })?;\n                let file_type = metadata.file_type();\n                if file_type.is_symlink() {\n                    anyhow::bail!(\n                        \"capsule projection contains a symbolic link: {}\",\n                        path.display()\n                    );\n                }\n                if file_type.is_dir() {\n                    inventory.directories.insert(relative_text.to_owned());\n                    walk(root, &path, inventory)?;\n                } else if file_type.is_file() {","sourceCodeStart":1612,"sourceCodeEnd":1648,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/lib.rs#L1612-L1648","documentation":"Thrown when `path.strip_prefix(root)` fails while walking a capsule projection, meaning an entry's path is not under the projection root. This is a safety check against path traversal — a projection entry escaping its declared root is treated as corruption/attack and aborts the walk.","triggerScenarios":"A capsule projection directory contains a symlink or hardlink whose resolved path lies outside the root, or the walk is invoked with mismatched root/directory arguments.","commonSituations":"Malicious or corrupted capsule content planting symlinks pointing outside the projection; calling walk with a subdirectory as `root` but a sibling path; inconsistent root after a rename/move.","solutions":["Do not pass mismatched root/directory arguments — directory must equal root or be beneath it.","Rebuild/re-extract the capsule projection; treat the existing projection as corrupted.","Verify the capsule source is trusted and free of out-of-root symlinks before projection.","If intentional, project only content confined to the root."],"exampleFix":"// before\nwalk(&subdir_root, &root, &mut inv)?; // mismatched\n// after\nwalk(&root, &root, &mut inv)?;","handlingStrategy":"validation","validationCode":"// reject out-of-root links before projecting\nfor entry in walk_source(capsule_dir) {\n    let meta = std::fs::symlink_metadata(&entry)?;\n    if meta.file_type().is_symlink() {\n        anyhow::bail!(\"refusing to project symlink: {}\", entry.display());\n    }\n}","typeGuard":"fn stays_under_root(root: &Path, p: &Path) -> bool { p.strip_prefix(root).is_ok() }","tryCatchPattern":"if let Err(e) = load_projection(root) {\n    if e.to_string().contains(\"escaped its root\") {\n        // treat projection as corrupted: rebuild from a trusted capsule source\n    }\n}","preventionTips":["Only project capsules from trusted, validated sources.","Reject symlinks at capsule build/pack time.","Never pass a root different from the directory being walked."],"tags":["security","path-traversal","filesystem","rust"],"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"}