From 1ce640d55ae37ad159a61e79ee269af03c04a776 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:06:49 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=92=20[security=20fix]=20Remove=20unsa?= =?UTF-8?q?fe=20path=20canonicalization=20in=20directory=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🎯 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> --- 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..4176c0a 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 = match normalized.components().last() { + Some(std::path::Component::Normal(_)) => true, + _ => false, + }; + 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