VYPR
Moderate severityNVD Advisory· Published Dec 23, 2022· Updated Apr 15, 2025

Tauri vulnerable to path traversal

CVE-2022-46171

Description

Tauri is a framework for building binaries for all major desktop platforms. The filesystem glob pattern wildcards *, ?, and [...] match file path literals and leading dots by default, which unintentionally exposes sub folder content of allowed paths. Scopes without the wildcards are not affected. As ** allows for sub directories the behavior there is also as expected. The issue has been patched in the latest release and was backported into the currently supported 1.x branches. There are no known workarounds at the time of publication.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Tauri filesystem glob patterns unintentionally match leading dots and literal path segments, exposing hidden files and subdirectories beyond intended scopes.

CVE-2022-46171 is a vulnerability in Tauri's filesystem scope validation. The glob pattern wildcards *, ?, and [...] match file path literals and leading dots by default, causing allowed paths to unintentionally expose subdirectory contents and dotfiles that should remain hidden [1]. The issue arises because the glob matching logic doesn't enforce require_literal_separator and require_literal_leading_dot options, allowing patterns like /dir/* to match files inside subdirectories such as /dir/subdir/file.txt and dotfiles like .hidden [2][3].

Exploitation requires the attacker to control or influence filesystem path patterns used in Tauri's scope configuration. An application that uses Tauri's allow_directory or other scope APIs with glob patterns can be tricked into granting broader access than intended. No authentication is needed if the attacker can provide the path patterns; the vulnerability is in the scope enforcement itself [1].

The impact is unauthorized access to files and directories, potentially exposing sensitive data that should be restricted. For example, dotfiles (e.g., .env, .ssh) and subdirectories could be read by the frontend or via Tauri API calls [2]. This breaks the intended isolation between the web frontend and the file system.

The issue has been patched in the latest Tauri release and backported to the supported 1.x branches. The fix adds require_literal_separator: true and require_literal_leading_dot: true (on Unix) to the glob match options [2][3]. No workarounds are available at the time of publication [1].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
tauricrates.io
>= 1.0.0, < 1.0.81.0.8
tauricrates.io
>= 1.1.0, < 1.1.31.1.3
tauricrates.io
>= 1.2.0, < 1.2.31.2.3
tauricrates.io
>= 2.0.0-alpha.0, < 2.0.0-alpha.22.0.0-alpha.2

Affected products

2
  • ghsa-coords
    Range: >= 1.0.0, < 1.0.8
  • tauri-apps/tauriv5
    Range: >= 1.0.0, < 1.0.8

Patches

3
14d567f7ecb2

chore: update tauri changelog

https://github.com/tauri-apps/tauriLucas NogueiraDec 22, 2022via ghsa
3 files changed · +17 2
  • core/tauri/Cargo.toml+1 1 modified
    @@ -10,7 +10,7 @@ license = "Apache-2.0 OR MIT"
     name = "tauri"
     readme = "README.md"
     repository = "https://github.com/tauri-apps/tauri"
    -version = "1.2.2"
    +version = "1.2.3"
     
     [package.metadata.docs.rs]
     no-default-features = true
    
  • core/tauri/CHANGELOG.md+15 0 modified
    @@ -1,5 +1,10 @@
     # Changelog
     
    +## \[1.2.3]
    +
    +- Fix the filesystem scope allowing sub-directories of the directory picked by the dialog when `recursive` option was `false`.
    +  - [f1b0ad6e](https://www.github.com/tauri-apps/tauri/commit/f1b0ad6e8b721cf1420a9a4b9be5b05c39941d16) Merge pull request from GHSA-6mv3-wm7j-h4w5 on 2022-12-22
    +
     ## \[1.2.2]
     
     - Invoke event listener in windows safely to avoid causing uncaught errors in windows that have loaded external urls
    @@ -67,6 +72,11 @@
     - Added the `user_agent` option when creating a window.
       - [a6c94119](https://www.github.com/tauri-apps/tauri/commit/a6c94119d8545d509723b147c273ca5edfe3729f) feat(core): expose user_agent to window config ([#5317](https://www.github.com/tauri-apps/tauri/pull/5317)) on 2022-10-02
     
    +## \[1.1.3]
    +
    +- Fix the filesystem scope allowing sub-directories of the directory picked by the dialog when `recursive` option was `false`.
    +  - [2654c0f4](https://www.github.com/tauri-apps/tauri/commit/2654c0f49da23434d36447d0908fa24e61ff5e4e) Merge pull request from GHSA-6mv3-wm7j-h4w5 on 2022-12-22
    +
     ## \[1.1.2]
     
     - Escape glob special characters in files/directories when dropping files or using the open/save dialogs.
    @@ -117,6 +127,11 @@
     - Add `exists` function to the fs module.
       - [3c62dbc9](https://www.github.com/tauri-apps/tauri/commit/3c62dbc902c904d35a7472ce72a969084c95fbbe) feat(api): Add `exists` function to the fs module. ([#5060](https://www.github.com/tauri-apps/tauri/pull/5060)) on 2022-09-15
     
    +## \[1.0.8]
    +
    +- Fix the filesystem scope allowing sub-directories of the directory picked by the dialog when `recursive` option was `false`.
    +  - [f0602e7c](https://www.github.com/tauri-apps/tauri/commit/f0602e7c294245ab6ef6fbf2a976ef398340ef58) Merge pull request from GHSA-6mv3-wm7j-h4w5 on 2022-12-22
    +
     ## \[1.0.7]
     
     - Escape glob special characters in files/directories when dropping files or using the open/save dialogs.
    
  • tooling/cli/metadata.json+1 1 modified
    @@ -3,6 +3,6 @@
         "version": "1.2.2",
         "node": ">= 10.0.0"
       },
    -  "tauri": "1.2.2",
    +  "tauri": "1.2.3",
       "tauri-build": "1.2.1"
     }
    
72389b00d7b4

Merge pull request from GHSA-6mv3-wm7j-h4w5

https://github.com/tauri-apps/tauriAmr BashirDec 22, 2022via ghsa
2 files changed · +103 24
  • .changes/glob-match-require_literal_separator.md+5 0 added
    @@ -0,0 +1,5 @@
    +---
    +"tauri": "patch"
    +---
    +
    +Fix the filesystem scope allowing sub-directories of the directory picked by the dialog when `recursive` option was `false`.
    
  • core/tauri/src/scope/fs.rs+98 24 modified
    @@ -141,7 +141,7 @@ impl Scope {
       /// Extend the allowed patterns with the given directory.
       ///
       /// After this function has been called, the frontend will be able to use the Tauri API to read
    -  /// the directory and all of its files and subdirectories.
    +  /// the directory and all of its files. If `recursive` is `true`, subdirectories will be accessible too.
       pub fn allow_directory<P: AsRef<Path>>(&self, path: P, recursive: bool) -> crate::Result<()> {
         let path = path.as_ref();
         {
    @@ -216,13 +216,22 @@ impl Scope {
     
         if let Ok(path) = path {
           let path: PathBuf = path.components().collect();
    +      let options = glob::MatchOptions {
    +        // this is needed so `/dir/*` doesn't match files within subdirectories such as `/dir/subdir/file.txt`
    +        // see: https://github.com/tauri-apps/tauri/security/advisories/GHSA-6mv3-wm7j-h4w5
    +        require_literal_separator: true,
    +        // dotfiles are not supposed to be exposed by default
    +        #[cfg(unix)]
    +        require_literal_leading_dot: true,
    +        ..Default::default()
    +      };
     
           let forbidden = self
             .forbidden_patterns
             .lock()
             .unwrap()
             .iter()
    -        .any(|p| p.matches_path(&path));
    +        .any(|p| p.matches_path_with(&path, options));
     
           if forbidden {
             false
    @@ -232,7 +241,7 @@ impl Scope {
               .lock()
               .unwrap()
               .iter()
    -          .any(|p| p.matches_path(&path));
    +          .any(|p| p.matches_path_with(&path, options));
             allowed
           }
         } else {
    @@ -269,32 +278,97 @@ mod tests {
       #[test]
       fn path_is_escaped() {
         let scope = new_scope();
    -    scope.allow_directory("/home/tauri/**", false).unwrap();
    -    assert!(scope.is_allowed("/home/tauri/**"));
    -    assert!(scope.is_allowed("/home/tauri/**/file"));
    -    assert!(!scope.is_allowed("/home/tauri/anyfile"));
    +    #[cfg(unix)]
    +    {
    +      scope.allow_directory("/home/tauri/**", false).unwrap();
    +      assert!(scope.is_allowed("/home/tauri/**"));
    +      assert!(scope.is_allowed("/home/tauri/**/file"));
    +      assert!(!scope.is_allowed("/home/tauri/anyfile"));
    +    }
    +    #[cfg(windows)]
    +    {
    +      scope.allow_directory("C:\\home\\tauri\\**", false).unwrap();
    +      assert!(scope.is_allowed("C:\\home\\tauri\\**"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\**\\file"));
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\anyfile"));
    +    }
     
         let scope = new_scope();
    -    scope.allow_file("/home/tauri/**").unwrap();
    -    assert!(scope.is_allowed("/home/tauri/**"));
    -    assert!(!scope.is_allowed("/home/tauri/**/file"));
    -    assert!(!scope.is_allowed("/home/tauri/anyfile"));
    +    #[cfg(unix)]
    +    {
    +      scope.allow_file("/home/tauri/**").unwrap();
    +      assert!(scope.is_allowed("/home/tauri/**"));
    +      assert!(!scope.is_allowed("/home/tauri/**/file"));
    +      assert!(!scope.is_allowed("/home/tauri/anyfile"));
    +    }
    +    #[cfg(windows)]
    +    {
    +      scope.allow_file("C:\\home\\tauri\\**").unwrap();
    +      assert!(scope.is_allowed("C:\\home\\tauri\\**"));
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\**\\file"));
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\anyfile"));
    +    }
    +
    +    let scope = new_scope();
    +    #[cfg(unix)]
    +    {
    +      scope.allow_directory("/home/tauri", true).unwrap();
    +      scope.forbid_directory("/home/tauri/**", false).unwrap();
    +      assert!(!scope.is_allowed("/home/tauri/**"));
    +      assert!(!scope.is_allowed("/home/tauri/**/file"));
    +      assert!(scope.is_allowed("/home/tauri/**/inner/file"));
    +      assert!(scope.is_allowed("/home/tauri/inner/folder/anyfile"));
    +      assert!(scope.is_allowed("/home/tauri/anyfile"));
    +    }
    +    #[cfg(windows)]
    +    {
    +      scope.allow_directory("C:\\home\\tauri", true).unwrap();
    +      scope
    +        .forbid_directory("C:\\home\\tauri\\**", false)
    +        .unwrap();
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\**"));
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\**\\file"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\**\\inner\\file"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\inner\\folder\\anyfile"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\anyfile"));
    +    }
     
         let scope = new_scope();
    -    scope.allow_directory("/home/tauri", true).unwrap();
    -    scope.forbid_directory("/home/tauri/**", false).unwrap();
    -    assert!(!scope.is_allowed("/home/tauri/**"));
    -    assert!(!scope.is_allowed("/home/tauri/**/file"));
    -    assert!(!scope.is_allowed("/home/tauri/**/inner/file"));
    -    assert!(scope.is_allowed("/home/tauri/inner/folder/anyfile"));
    -    assert!(scope.is_allowed("/home/tauri/anyfile"));
    +    #[cfg(unix)]
    +    {
    +      scope.allow_directory("/home/tauri", true).unwrap();
    +      scope.forbid_file("/home/tauri/**").unwrap();
    +      assert!(!scope.is_allowed("/home/tauri/**"));
    +      assert!(scope.is_allowed("/home/tauri/**/file"));
    +      assert!(scope.is_allowed("/home/tauri/**/inner/file"));
    +      assert!(scope.is_allowed("/home/tauri/anyfile"));
    +    }
    +    #[cfg(windows)]
    +    {
    +      scope.allow_directory("C:\\home\\tauri", true).unwrap();
    +      scope.forbid_file("C:\\home\\tauri\\**").unwrap();
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\**"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\**\\file"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\**\\inner\\file"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\anyfile"));
    +    }
     
         let scope = new_scope();
    -    scope.allow_directory("/home/tauri", true).unwrap();
    -    scope.forbid_file("/home/tauri/**").unwrap();
    -    assert!(!scope.is_allowed("/home/tauri/**"));
    -    assert!(scope.is_allowed("/home/tauri/**/file"));
    -    assert!(scope.is_allowed("/home/tauri/**/inner/file"));
    -    assert!(scope.is_allowed("/home/tauri/anyfile"));
    +    #[cfg(unix)]
    +    {
    +      scope.allow_directory("/home/tauri", false).unwrap();
    +      assert!(scope.is_allowed("/home/tauri/**"));
    +      assert!(!scope.is_allowed("/home/tauri/**/file"));
    +      assert!(!scope.is_allowed("/home/tauri/**/inner/file"));
    +      assert!(scope.is_allowed("/home/tauri/anyfile"));
    +    }
    +    #[cfg(windows)]
    +    {
    +      scope.allow_directory("C:\\home\\tauri", false).unwrap();
    +      assert!(scope.is_allowed("C:\\home\\tauri\\**"));
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\**\\file"));
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\**\\inner\\file"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\anyfile"));
    +    }
       }
     }
    
f0602e7c2942

Merge pull request from GHSA-6mv3-wm7j-h4w5

https://github.com/tauri-apps/tauriAmr BashirDec 22, 2022via ghsa
2 files changed · +103 24
  • .changes/glob-match-require_literal_separator.md+5 0 added
    @@ -0,0 +1,5 @@
    +---
    +"tauri": "patch"
    +---
    +
    +Fix the filesystem scope allowing sub-directories of the directory picked by the dialog when `recursive` option was `false`.
    
  • core/tauri/src/scope/fs.rs+98 24 modified
    @@ -141,7 +141,7 @@ impl Scope {
       /// Extend the allowed patterns with the given directory.
       ///
       /// After this function has been called, the frontend will be able to use the Tauri API to read
    -  /// the directory and all of its files and subdirectories.
    +  /// the directory and all of its files. If `recursive` is `true`, subdirectories will be accessible too.
       pub fn allow_directory<P: AsRef<Path>>(&self, path: P, recursive: bool) -> crate::Result<()> {
         let path = path.as_ref();
         {
    @@ -216,13 +216,22 @@ impl Scope {
     
         if let Ok(path) = path {
           let path: PathBuf = path.components().collect();
    +      let options = glob::MatchOptions {
    +        // this is needed so `/dir/*` doesn't match files within subdirectories such as `/dir/subdir/file.txt`
    +        // see: https://github.com/tauri-apps/tauri/security/advisories/GHSA-6mv3-wm7j-h4w5
    +        require_literal_separator: true,
    +        // dotfiles are not supposed to be exposed by default
    +        #[cfg(unix)]
    +        require_literal_leading_dot: true,
    +        ..Default::default()
    +      };
     
           let forbidden = self
             .forbidden_patterns
             .lock()
             .unwrap()
             .iter()
    -        .any(|p| p.matches_path(&path));
    +        .any(|p| p.matches_path_with(&path, options));
     
           if forbidden {
             false
    @@ -232,7 +241,7 @@ impl Scope {
               .lock()
               .unwrap()
               .iter()
    -          .any(|p| p.matches_path(&path));
    +          .any(|p| p.matches_path_with(&path, options));
             allowed
           }
         } else {
    @@ -269,32 +278,97 @@ mod tests {
       #[test]
       fn path_is_escaped() {
         let scope = new_scope();
    -    scope.allow_directory("/home/tauri/**", false).unwrap();
    -    assert!(scope.is_allowed("/home/tauri/**"));
    -    assert!(scope.is_allowed("/home/tauri/**/file"));
    -    assert!(!scope.is_allowed("/home/tauri/anyfile"));
    +    #[cfg(unix)]
    +    {
    +      scope.allow_directory("/home/tauri/**", false).unwrap();
    +      assert!(scope.is_allowed("/home/tauri/**"));
    +      assert!(scope.is_allowed("/home/tauri/**/file"));
    +      assert!(!scope.is_allowed("/home/tauri/anyfile"));
    +    }
    +    #[cfg(windows)]
    +    {
    +      scope.allow_directory("C:\\home\\tauri\\**", false).unwrap();
    +      assert!(scope.is_allowed("C:\\home\\tauri\\**"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\**\\file"));
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\anyfile"));
    +    }
     
         let scope = new_scope();
    -    scope.allow_file("/home/tauri/**").unwrap();
    -    assert!(scope.is_allowed("/home/tauri/**"));
    -    assert!(!scope.is_allowed("/home/tauri/**/file"));
    -    assert!(!scope.is_allowed("/home/tauri/anyfile"));
    +    #[cfg(unix)]
    +    {
    +      scope.allow_file("/home/tauri/**").unwrap();
    +      assert!(scope.is_allowed("/home/tauri/**"));
    +      assert!(!scope.is_allowed("/home/tauri/**/file"));
    +      assert!(!scope.is_allowed("/home/tauri/anyfile"));
    +    }
    +    #[cfg(windows)]
    +    {
    +      scope.allow_file("C:\\home\\tauri\\**").unwrap();
    +      assert!(scope.is_allowed("C:\\home\\tauri\\**"));
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\**\\file"));
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\anyfile"));
    +    }
    +
    +    let scope = new_scope();
    +    #[cfg(unix)]
    +    {
    +      scope.allow_directory("/home/tauri", true).unwrap();
    +      scope.forbid_directory("/home/tauri/**", false).unwrap();
    +      assert!(!scope.is_allowed("/home/tauri/**"));
    +      assert!(!scope.is_allowed("/home/tauri/**/file"));
    +      assert!(scope.is_allowed("/home/tauri/**/inner/file"));
    +      assert!(scope.is_allowed("/home/tauri/inner/folder/anyfile"));
    +      assert!(scope.is_allowed("/home/tauri/anyfile"));
    +    }
    +    #[cfg(windows)]
    +    {
    +      scope.allow_directory("C:\\home\\tauri", true).unwrap();
    +      scope
    +        .forbid_directory("C:\\home\\tauri\\**", false)
    +        .unwrap();
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\**"));
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\**\\file"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\**\\inner\\file"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\inner\\folder\\anyfile"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\anyfile"));
    +    }
     
         let scope = new_scope();
    -    scope.allow_directory("/home/tauri", true).unwrap();
    -    scope.forbid_directory("/home/tauri/**", false).unwrap();
    -    assert!(!scope.is_allowed("/home/tauri/**"));
    -    assert!(!scope.is_allowed("/home/tauri/**/file"));
    -    assert!(!scope.is_allowed("/home/tauri/**/inner/file"));
    -    assert!(scope.is_allowed("/home/tauri/inner/folder/anyfile"));
    -    assert!(scope.is_allowed("/home/tauri/anyfile"));
    +    #[cfg(unix)]
    +    {
    +      scope.allow_directory("/home/tauri", true).unwrap();
    +      scope.forbid_file("/home/tauri/**").unwrap();
    +      assert!(!scope.is_allowed("/home/tauri/**"));
    +      assert!(scope.is_allowed("/home/tauri/**/file"));
    +      assert!(scope.is_allowed("/home/tauri/**/inner/file"));
    +      assert!(scope.is_allowed("/home/tauri/anyfile"));
    +    }
    +    #[cfg(windows)]
    +    {
    +      scope.allow_directory("C:\\home\\tauri", true).unwrap();
    +      scope.forbid_file("C:\\home\\tauri\\**").unwrap();
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\**"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\**\\file"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\**\\inner\\file"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\anyfile"));
    +    }
     
         let scope = new_scope();
    -    scope.allow_directory("/home/tauri", true).unwrap();
    -    scope.forbid_file("/home/tauri/**").unwrap();
    -    assert!(!scope.is_allowed("/home/tauri/**"));
    -    assert!(scope.is_allowed("/home/tauri/**/file"));
    -    assert!(scope.is_allowed("/home/tauri/**/inner/file"));
    -    assert!(scope.is_allowed("/home/tauri/anyfile"));
    +    #[cfg(unix)]
    +    {
    +      scope.allow_directory("/home/tauri", false).unwrap();
    +      assert!(scope.is_allowed("/home/tauri/**"));
    +      assert!(!scope.is_allowed("/home/tauri/**/file"));
    +      assert!(!scope.is_allowed("/home/tauri/**/inner/file"));
    +      assert!(scope.is_allowed("/home/tauri/anyfile"));
    +    }
    +    #[cfg(windows)]
    +    {
    +      scope.allow_directory("C:\\home\\tauri", false).unwrap();
    +      assert!(scope.is_allowed("C:\\home\\tauri\\**"));
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\**\\file"));
    +      assert!(!scope.is_allowed("C:\\home\\tauri\\**\\inner\\file"));
    +      assert!(scope.is_allowed("C:\\home\\tauri\\anyfile"));
    +    }
       }
     }
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.