{"record":{"id":"8c24b5764e00db85","repo":"BigPizzaV3/CodexPlusPlus","slug":"parent-traversal-is-unsupported","errorCode":null,"errorMessage":"Parent traversal is unsupported","messagePattern":"Parent traversal is unsupported","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/native_browser.rs","lineNumber":127,"sourceCode":"fn plain_path(path: &Path) -> Result<()> {\n    ensure!(path.is_absolute(), \"Expected an absolute local path\");\n    for ancestor in path.ancestors() {\n        if let Ok(meta) = fs::symlink_metadata(ancestor) {\n            ensure!(\n                !meta.file_type().is_symlink(),\n                \"Linked paths are unsupported\"\n            );\n            #[cfg(windows)]\n            {\n                use std::os::windows::fs::MetadataExt;\n                ensure!(\n                    meta.file_attributes() & 0x400 == 0,\n                    \"Reparse paths are unsupported\"\n                );\n            }\n        }\n    }\n    ensure!(\n        !path\n            .components()\n            .any(|c| matches!(c, std::path::Component::ParentDir)),\n        \"Parent traversal is unsupported\"\n    );\n    Ok(())\n}\n\n// Deny directory deletion/renaming while a Windows transaction uses its descendants.\n// Open root-first with OPEN_REPARSE_POINT so no checked parent can become a junction.\nfn pin_parents(path: &Path) -> Result<Vec<File>> {\n    plain_path(path)?;\n    let mut guards = Vec::new();\n    #[cfg(windows)]\n    {\n        use std::os::windows::fs::{MetadataExt, OpenOptionsExt};\n        let mut parents: Vec<_> = path.ancestors().skip(1).collect();\n        parents.reverse();","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/native_browser.rs#L109-L145","documentation":"As the final plain_path check, the component list of the path is scanned for Component::ParentDir (`..`). Parent traversal could escape the intended root after pinning, defeating the isolation contract, so any path containing `..` is rejected.","triggerScenarios":"pin_parents, selected_key, discover, prepare, restore_all, or reconcile_contract given a path built with `..` segments — e.g. root.join(\"..\")\\sibling or user-supplied relative-ish input that includes .. even when overall absolute.","commonSituations":"User config like `state_root = \"C:\\\\codex\\\\..\\\\codex-browser\"`; code normalizing via join(\"..\") instead of canonicalize; untrusted input containing .. reaching the browser path configuration.","solutions":["Remove `..` from the configured path and express the real absolute location directly","Normalize the path before calling: std::path::absolute plus lexical cleanup, or fs::canonicalize (after ensuring no links)","Sanitize untrusted input: reject any path whose components include ParentDir before passing to the API","Keep paths built with PathBuf::join from trusted constants rather than string concatenation of user input"],"exampleFix":"// before\nplain_path(&Path::new(\"C:\\\\codex\\\\..\\\\codex-browser\\\\state\"))?;\n// after\nplain_path(&Path::new(\"C:\\\\codex-browser\\\\state\"))?;","handlingStrategy":"validation","validationCode":"fn contains_parent_dir(p: &Path) -> bool {\n    p.components().any(|c| matches!(c, std::path::Component::ParentDir))\n}","typeGuard":"fn is_traversal_free(p: &Path) -> bool {\n    !p.components().any(|c| matches!(c, std::path::Component::ParentDir))\n}","tryCatchPattern":"match plain_path(p) {\n    Err(e) if e.to_string().contains(\"Parent traversal\") => {\n        eprintln!(\"path contains '..'; specify the real absolute location instead\");\n    }\n    other => other?,\n}","preventionTips":["Reject '..' segments in user-supplied paths at config validation time","Normalize paths with canonicalize/absolute before storing them","Build paths with PathBuf::join on trusted roots, not string concatenation"],"tags":["rust","path-safety","traversal"],"backgroundTag":"path-traversal-blocked","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}