{"record":{"id":"606cd2f9df8d5df1","repo":"xai-org/grok-build","slug":"path-is-outside-the-memory-directory","errorCode":null,"errorMessage":"path {:?} is outside the memory directory {:?}","messagePattern":"path (.+?) is outside the memory directory (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/codegen/xai-grok-memory/src/storage.rs","lineNumber":278,"sourceCode":"    /// Both the path and the memory root must be canonicalizable; if either fails, the read is rejected.\n    pub fn read_file(\n        &self,\n        path: &Path,\n        from: Option<usize>,\n        lines: Option<usize>,\n    ) -> std::io::Result<String> {\n        // Security: canonicalize both sides; fail hard if either doesn't exist\n        let canonical = dunce::canonicalize(path)?;\n        let canonical_global = dunce::canonicalize(&self.global_dir).map_err(|e| {\n            std::io::Error::new(\n                std::io::ErrorKind::NotFound,\n                format!(\"memory directory {:?} does not exist: {e}\", self.global_dir),\n            )\n        })?;\n\n        // Fail-closed caveat for paths longer than MAX_PATH: see workspace clippy.toml\n        if !canonical.starts_with(&canonical_global) {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::PermissionDenied,\n                format!(\n                    \"path {:?} is outside the memory directory {:?}\",\n                    path, self.global_dir\n                ),\n            ));\n        }\n\n        // Read the canonicalized path, not the original, to prevent TOCTOU races.\n        let content = std::fs::read_to_string(&canonical)?;\n\n        let from = from.unwrap_or(0);\n        match lines {\n            Some(count) => {\n                let selected: Vec<&str> = content.lines().skip(from).take(count).collect();\n                Ok(selected.join(\"\\n\"))\n            }\n            None if from > 0 => {","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-memory/src/storage.rs#L260-L296","documentation":"MemoryStorage::read_file canonicalizes the requested path and requires it to be inside the canonicalized global memory directory; otherwise it returns this PermissionDenied io::Error. It is a deliberate path-traversal guard so callers cannot read arbitrary files outside memory storage.","triggerScenarios":"Calling read_file with a path containing ../ escapes, a symlink resolving outside the memory root, an absolute path to another location, or a path inside a different profile directory.","commonSituations":"Constructing file names from user or LLM-supplied input without sanitization; symlinked memory directories; tests asserting rejection (test_storage_read_file_rejects_outside_path).","solutions":["Resolve the requested file relative to the memory directory root and pass a path inside it","Reject/clean ../ segments and canonicalize user input before calling read_file","Remove or re-point symlinks that escape the memory directory","If access outside is intended, configure a different storage root that contains the target"],"exampleFix":"// before\nlet p = std::path::PathBuf::from(user_supplied); // may be ../../etc/passwd\nlet s = storage.read_file(&p, None, None)?;\n// after\nlet p = memory_root.join(user_supplied);\nlet p = dunce::canonicalize(&p)?;\nassert!(p.starts_with(&memory_root));\nlet s = storage.read_file(&p, None, None)?;","handlingStrategy":"validation","validationCode":"fn is_inside_memory_dir(path: &Path, root: &Path) -> std::io::Result<bool> {\n    let c = dunce::canonicalize(path)?;\n    let r = dunce::canonicalize(root)?;\n    Ok(c.starts_with(r))\n}","typeGuard":"fn safe_memory_path(path: &Path, root: &Path) -> Option<PathBuf> {\n    let c = dunce::canonicalize(path).ok()?;\n    let r = dunce::canonicalize(root).ok()?;\n    if c.starts_with(r) { Some(c) } else { None }\n}","tryCatchPattern":"match storage.read_file(&path, None, None) {\n    Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {\n        eprintln!(\"refusing path outside memory dir: {path:?}\");\n    }\n    other => other?,\n}","preventionTips":["Never pass raw user/LLM-supplied paths; join them onto the memory root","Strip ../ components and canonicalize before calling","Avoid symlinks inside the memory dir that escape the root","Unit-test traversal attempts like test_storage_read_file_rejects_outside_path"],"tags":["security","path-traversal","filesystem","io"],"backgroundTag":"path-traversal-blocked","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}