{"record":{"id":"a01927f944cdf60f","repo":"FyroxEngine/Fyrox","slug":"path-may-not-start-with","errorCode":null,"errorMessage":"Path may not start with ..","messagePattern":"Path may not start with \\.\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"fyrox-resource/src/io.rs","lineNumber":217,"sourceCode":"/// and replace \\ with /. There is no requirement that any part of the path actually exists.\n/// The path \".\" is returned if the resulting path would otherwise be empty.\n///\n/// Because the file system is not accessed, all paths must be relative to the project root,\n/// and this function will return an error if the path tries to go outside of it, such as by .. directories\n/// or by being an absolute path.\npub fn normalize_path(path: impl AsRef<Path>) -> Result<PathBuf, FileError> {\n    let components = path.as_ref().components();\n    let mut ret = PathBuf::new();\n\n    for component in components {\n        match component {\n            Component::Prefix(..) | Component::RootDir => {\n                return Err(format!(\"Invalid path: {:?}\", path.as_ref()).into());\n            }\n            Component::CurDir => {}\n            Component::ParentDir => {\n                if !ret.pop() {\n                    panic!(\"Path may not start with ..\");\n                }\n            }\n            Component::Normal(c) => {\n                ret.push(c);\n            }\n        }\n    }\n\n    if ret.as_os_str().is_empty() {\n        return Ok(\".\".into());\n    }\n\n    // The resource registry uses normalized paths with `/` slashes, and this step is needed\n    // mostly on Windows which uses `\\` slashes.\n    Ok(replace_slashes(ret))\n}\n\nimpl ResourceIo for FsResourceIo {","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/FyroxEngine/Fyrox/blob/76c91aad8eca488ce527b1af707be8b3b24ad72d/fyrox-resource/src/io.rs#L199-L235","documentation":"ResourceIo::normalize_path (via Path::components) rejects relative paths that begin with a ParentDir (`..`) when there is no existing component to pop. Since the path being normalized is relative (absolute paths/prefixes are rejected earlier), a leading `..` has nothing to pop, so the function panics. This guards against path escapes from the resource base directory.","triggerScenarios":"Calling canonicalize_path/normalize_path with a relative path like \"../assets/tile.png\" or \"..\\\\foo.png\"; building resource paths by string concatenation that produce leading `..`; passing user-supplied resource paths unvalidated.","commonSituations":"Mods/plugins referencing resources outside the base directory; portable save/config files that embed `..` paths; path traversal attempts through user input.","solutions":["Remove or resolve the leading `..` before passing the path (make it relative to the resource base).","Validate input paths and reject/rewrite any that start with `..`.","If the target truly lives outside the resource root, relocate it under the root or use an absolute path through the file system API instead."],"exampleFix":"// before\nlet path = Path::new(\"../textures/rock.png\");\nresource_manager.request::<Texture>(path); // panics\n// after\nlet path = Path::new(\"textures/rock.png\"); // relative to the resource base\nresource_manager.request::<Texture>(path);","handlingStrategy":"validation","validationCode":"fn is_safe_relative_path(p: &Path) -> bool {\n    !p.is_absolute()\n        && !p.components().any(|c| matches!(c, std::path::Component::ParentDir))\n        && p.components().next().is_some()\n}","typeGuard":"fn resource_path_ok(p: &Path) -> bool { !p.starts_with(\"..\") && p.is_relative() }","tryCatchPattern":null,"preventionTips":["Normalize user-supplied resource paths to be relative to the resource base before use.","Reject or sanitize any path containing `..` at input boundaries (mod loaders, save files, drag-and-drop).","Keep all assets inside the resource base directory and reference them by base-relative paths."],"tags":["panic","path","validation","resources"],"backgroundTag":"path-traversal-blocked","analyzedSha":"76c91aad8eca488ce527b1af707be8b3b24ad72d","analyzedAt":"2026-09-10T16:04:01.633Z","contentChangedAt":"2026-09-10T16:04:01.633Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}