{"record":{"id":"06cfe583af3ddc18","repo":"tinyhumansai/openhuman","slug":"dest-path-resolves-outside-the-downloads-root","errorCode":null,"errorMessage":"dest_path resolves outside the downloads root","messagePattern":"dest_path resolves outside the downloads root","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/tools/impl/network/curl.rs","lineNumber":82,"sourceCode":"            match component {\n                Component::Normal(_) => {}\n                Component::CurDir => {}\n                Component::ParentDir => {\n                    anyhow::bail!(\"dest_path may not contain '..'\");\n                }\n                Component::Prefix(_) | Component::RootDir => {\n                    anyhow::bail!(\"dest_path must be relative\");\n                }\n            }\n        }\n\n        let root = self.workspace_dir.join(&self.dest_subdir);\n        let resolved = root.join(p);\n\n        // Belt-and-braces: ensure the resolved path still lives under root.\n        // Lexical check is sufficient because we already rejected `..`.\n        if !resolved.starts_with(&root) {\n            anyhow::bail!(\"dest_path resolves outside the downloads root\");\n        }\n\n        Ok(resolved)\n    }\n\n    async fn validate_url(&self, raw_url: &str) -> anyhow::Result<String> {\n        validate_url_with_dns_check(raw_url, &self.allowed_domains).await\n    }\n\n    fn default_filename_from_url(url: &str) -> String {\n        let after_scheme = url.split_once(\"://\").map(|(_, rest)| rest).unwrap_or(url);\n        let path_part = after_scheme.split_once('/').map(|(_, p)| p).unwrap_or(\"\");\n        let last = path_part\n            .split('?')\n            .next()\n            .unwrap_or(\"\")\n            .rsplit('/')\n            .next()","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/tools/impl/network/curl.rs#L64-L100","documentation":"Belt-and-braces containment check: although the individual components passed, the final joined path failed to verify as living under <workspace>/<dest_subdir>, so the download is refused rather than written outside the jail.","triggerScenarios":"Thrown at src/openhuman/tools/impl/network/curl.rs:82 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Simplify dest_path to a normal relative filename and retry","Report the input if a plain relative path still triggers this check, as it may indicate a path-normalization bug"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}