From 8c50fc8aa9cabf4bd2552481a25744f8cb8f72b3 Mon Sep 17 00:00:00 2001 From: Horizontal42 <75383519+Horizontal42@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:35:45 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=92=20[security=20fix]=20Remove=20unsa?= =?UTF-8?q?fe=20path=20canonicalization=20in=20directory=20gate=20(#111)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🔒 [security fix] Remove unsafe path canonicalization in directory gate 🎯 What: Removed filesystem-level path canonicalization in the DataDirGate check (`canon_or_raw`). ⚠️ Risk: An attacker could bypass directory authorization by creating a symlink to an authorized directory, allowing them to redirect arbitrary path reads/writes via TOCTOU (Time-of-Check to Time-of-Use) attacks or misleading unverified paths. 🛡️ Solution: Replaced `fs::canonicalize` with purely lexical path normalization (resolving `.` and `..` in memory) to ensure strict string match validation without following symlinks. Ensure relative paths with `..` that go above the start are handled securely. Co-authored-by: Horizontal42 <75383519+Horizontal42@users.noreply.github.com> * 🔒 [security fix] Remove unsafe path canonicalization in directory gate 🎯 What: Removed filesystem-level path canonicalization in the DataDirGate check (`canon_or_raw`). ⚠️ Risk: An attacker could bypass directory authorization by creating a symlink to an authorized directory, allowing them to redirect arbitrary path reads/writes via TOCTOU (Time-of-Check to Time-of-Use) attacks or misleading unverified paths. 🛡️ Solution: Replaced `fs::canonicalize` with purely lexical path normalization (resolving `.` and `..` in memory) to ensure strict string match validation without following symlinks. Ensure relative paths with `..` that go above the start are handled securely without dropping components incorrectly. Added proper Iterator methods to appease clippy. Co-authored-by: Horizontal42 <75383519+Horizontal42@users.noreply.github.com> --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- src-tauri/src/main.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 3823064..9a32958 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -46,7 +46,25 @@ struct DataDirGate { } fn canon_or_raw(p: &Path) -> PathBuf { - fs::canonicalize(p).unwrap_or_else(|_| p.to_path_buf()) + let mut normalized = PathBuf::new(); + for component in p.components() { + match component { + std::path::Component::ParentDir => { + let can_pop = matches!( + normalized.components().next_back(), + Some(std::path::Component::Normal(_)) + ); + if can_pop { + normalized.pop(); + } else if !normalized.has_root() { + normalized.push(component); + } + } + std::path::Component::CurDir => {} + _ => normalized.push(component), + } + } + normalized } /// Exact match against an authorized folder, compared canonicalized so a