{"record":{"id":"8dbd21dcb8ad3caf","repo":"astrid-runtime/astrid","slug":"capsule-cache-path-is-outside-the-durable-registry","errorCode":null,"errorMessage":"capsule cache path is outside the durable registry cache","messagePattern":"capsule cache path is outside the durable registry cache","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/lib.rs","lineNumber":1583,"sourceCode":"            false,\n            None,\n            &self.workspace_layout,\n        )\n        .map_err(|error| anyhow::anyhow!(\"resolve durable capsule cache target: {error}\"))\n    }\n\n    /// Validate the disposable cache path against an exact owner snapshot.\n    #[cfg(not(all(target_arch = \"wasm32\", target_os = \"unknown\")))]\n    fn validate_published_cache_path(\n        &self,\n        dir: &Path,\n        principal: &PrincipalId,\n        manifest: &astrid_capsule_types::manifest::CapsuleManifest,\n        snapshot: &astrid_storage::CapsulePackageSnapshot,\n    ) -> anyhow::Result<()> {\n        let cache_root = self.astrid_home.run_dir().join(\"capsules\");\n        let relative = dir.strip_prefix(&cache_root).map_err(|_| {\n            anyhow::anyhow!(\"capsule cache path is outside the durable registry cache\")\n        })?;\n        astrid_core::platform_fs::verify_no_redirects(dir)\n            .map_err(|error| anyhow::anyhow!(\"capsule cache path is redirected: {error}\"))?;\n        let components: Vec<String> = relative\n            .components()\n            .map(|component| match component {\n                std::path::Component::Normal(value) => Ok(value.to_string_lossy().into_owned()),\n                _ => Err(anyhow::anyhow!(\n                    \"capsule cache path contains unsafe components\"\n                )),\n            })\n            .collect::<anyhow::Result<_>>()?;\n        if components.len() != 3 {\n            anyhow::bail!(\"capsule cache path does not contain owner/id/digest components\");\n        }\n        let uid = self\n            .principal_directory\n            .uid_for(principal)","sourceCodeStart":1565,"sourceCodeEnd":1601,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/lib.rs#L1565-L1601","documentation":"Static error from `dir.strip_prefix(cache_root)` failing in validate_published_cache_path: the candidate cache directory is not under `<astrid_home>/run/capsules`, so it cannot be a legitimate durable-registry cache path. This is a hard security boundary check with no inner cause.","triggerScenarios":"validate_published_cache_path is handed a `dir` outside run_dir().join(\"capsules\") — e.g. a path computed from a different home, a tampered registry snapshot, or an absolute path substituted for the computed target.","commonSituations":"ASTRID_HOME changed between resolution and validation; registry snapshot fields manually edited; code passing an arbitrary directory into the validator; mounted/aliased home producing lexically different paths.","solutions":["Ensure the dir passed in was produced by published_cache_target from the same astrid_home","Check that ASTRID_HOME / astrid_home has not changed between target resolution and validation","Recompute the cache target instead of passing a user-supplied path","If using mounts/aliases, use the canonical home path consistently"],"exampleFix":"// before\nvalidate(&some_user_path, principal, manifest, snapshot)?;\n// after\nlet target = published_cache_target(principal, manifest, snapshot)?;\nvalidate(&target, principal, manifest, snapshot)?;","handlingStrategy":"validation","validationCode":"let cache_root = astrid_home.run_dir().join(\"capsules\");\nif dir.strip_prefix(&cache_root).is_err() {\n    panic!(\"refusing to validate path outside durable cache root: {}\", dir.display());\n}","typeGuard":"fn inside_cache_root(dir: &Path, home: &AstridHome) -> bool {\n    dir.strip_prefix(home.run_dir().join(\"capsules\")).is_ok()\n}","tryCatchPattern":null,"preventionTips":["Only pass resolver-produced paths to validate_published_cache_path","Never accept user-supplied cache directories","Keep ASTRID_HOME stable for the lifetime of a kernel instance"],"tags":["path-safety","security","cache","boundary-check"],"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"}