Improper Scope Validation in the open Endpoint of tauri-plugin-shell
Description
The Tauri shell plugin allows access to the system shell. Prior to 2.2.1, the Tauri shell plugin exposes functionality to execute code and open programs on the system. The open endpoint of this plugin is designed to allow open functionality with the system opener (e.g. xdg-open on Linux). This was meant to be restricted to a reasonable number of protocols like https or mailto by default. This default restriction was not functional due to improper validation of the allowed protocols, allowing for potentially dangerous protocols like file://, smb://, or nfs:// and others to be opened by the system registered protocol handler. By passing untrusted user input to the open endpoint these potentially dangerous protocols can be abused to gain remote code execution on the system. This either requires direct exposure of the endpoint to application users or code execution in the frontend of a Tauri application. This vulnerability is fixed in 2.2.1.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
tauri-plugin-shellcrates.io | < 2.2.1 | 2.2.1 |
@tauri-apps/plugin-shellnpm | < 2.2.1 | 2.2.1 |
Affected products
1- Range: < 2.2.1
Patches
19cf0390a5249Merge commit from fork
11 files changed · +44 −11
.changes/fix-shell-open-scope.md+7 −0 added@@ -0,0 +1,7 @@ +--- +"shell": patch:bug +"shell-js": patch:bug +--- + +Apply the default open validation regex `^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+` when the open configuration is not set, preventing unchecked input from being used in this scenario (previously the plugin would skip validation when it should disable all calls). This keeps backwards compatibility while still fixing this vulnerability. +The scope is no longer validated for Rust calls via `ShellExt::shell()` so if you need to block JavaScript from calling the API you can simply set `tauri.conf.json > plugins > shell > open` to `false`.
examples/api/src-tauri/capabilities/base.json+1 −1 modified@@ -53,7 +53,7 @@ } ] }, - "shell:allow-open", + "shell:default", "shell:allow-kill", "shell:allow-stdin-write", "process:allow-exit",
package.json+2 −1 modified@@ -35,5 +35,6 @@ }, "engines": { "pnpm": "^10.0.0" - } + }, + "packageManager": "pnpm@10.6.3+sha512.bb45e34d50a9a76e858a95837301bfb6bd6d35aea2c5d52094fa497a467c43f5c440103ce2511e9e0a2f89c3d6071baac3358fc68ac6fb75e2ceb3d2736065e6" }
plugins/shell/permissions/autogenerated/reference.md+1 −1 modified@@ -5,7 +5,7 @@ shell functionality is exposed by default. #### Granted Permissions -It allows to use the `open` functionality without any specific +It allows to use the `open` functionality with a reasonable scope pre-configured. It will allow opening `http(s)://`, `tel:` and `mailto:` links.
plugins/shell/permissions/default.toml+1 −1 modified@@ -7,7 +7,7 @@ shell functionality is exposed by default. #### Granted Permissions -It allows to use the `open` functionality without any specific +It allows to use the `open` functionality with a reasonable scope pre-configured. It will allow opening `http(s)://`, `tel:` and `mailto:` links. """
plugins/shell/permissions/schemas/schema.json+1 −1 modified@@ -355,7 +355,7 @@ "markdownDescription": "Denies the stdin_write command without any pre-configured scope." }, { - "description": "This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality without any specific\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n\n#### This default permission set includes:\n\n- `allow-open`", + "description": "This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality with a reasonable\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n", "type": "string", "const": "default", "markdownDescription": "This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality without any specific\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n\n#### This default permission set includes:\n\n- `allow-open`"
plugins/shell/src/commands.rs+1 −1 modified@@ -311,5 +311,5 @@ pub async fn open<R: Runtime>( path: String, with: Option<Program>, ) -> crate::Result<()> { - shell.open(path, with) + crate::open::open(Some(&shell.open_scope), path, with) }
plugins/shell/src/config.rs+4 −1 modified@@ -18,6 +18,9 @@ pub struct Config { #[serde(untagged, deny_unknown_fields)] #[non_exhaustive] pub enum ShellAllowlistOpen { + /// Shell open API allowlist is not defined by the user. + /// In this case we add the default validation regex (same as [`Self::Flag(true)`]). + Unset, /// If the shell open API should be enabled. /// /// If enabled, the default validation regex (`^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+`) is used. @@ -35,6 +38,6 @@ pub enum ShellAllowlistOpen { impl Default for ShellAllowlistOpen { fn default() -> Self { - Self::Flag(false) + Self::Unset } }
plugins/shell/src/lib.rs+3 −2 modified@@ -75,7 +75,7 @@ impl<R: Runtime> Shell<R> { #[deprecated(since = "2.1.0", note = "Use tauri-plugin-opener instead.")] #[allow(deprecated)] pub fn open(&self, path: impl Into<String>, with: Option<open::Program>) -> Result<()> { - open::open(&self.open_scope, path.into(), with) + open::open(None, path.into(), with) } /// Open a (url) path with a default or specific browser opening program. @@ -147,7 +147,8 @@ pub fn init<R: Runtime>() -> TauriPlugin<R, Option<config::Config>> { fn open_scope(open: &config::ShellAllowlistOpen) -> scope::OpenScope { let shell_scope_open = match open { config::ShellAllowlistOpen::Flag(false) => None, - config::ShellAllowlistOpen::Flag(true) => { + // we want to add a basic regex validation even if the config is not set + config::ShellAllowlistOpen::Unset | config::ShellAllowlistOpen::Flag(true) => { Some(Regex::new(r"^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+").unwrap()) } config::ShellAllowlistOpen::Validate(validator) => {
plugins/shell/src/open.rs+16 −2 modified@@ -119,6 +119,20 @@ impl Program { /// }); /// ``` #[deprecated(since = "2.1.0", note = "Use tauri-plugin-opener instead.")] -pub fn open<P: AsRef<str>>(scope: &OpenScope, path: P, with: Option<Program>) -> crate::Result<()> { - scope.open(path.as_ref(), with).map_err(Into::into) +pub fn open<P: AsRef<str>>( + scope: Option<&OpenScope>, + path: P, + with: Option<Program>, +) -> crate::Result<()> { + // validate scope if we have any (JS calls) + if let Some(scope) = scope { + scope.open(path.as_ref(), with).map_err(Into::into) + } else { + // when running directly from Rust code we don't need to validate the path + match with.map(Program::name) { + Some(program) => ::open::with_detached(path.as_ref(), program), + None => ::open::that_detached(path.as_ref()), + } + .map_err(Into::into) + } }
plugins/shell/src/scope.rs+7 −0 modified@@ -142,6 +142,7 @@ impl ScopeAllowedArg { /// Scope for the open command pub struct OpenScope { /// The validation regex that `shell > open` paths must match against. + /// When set to `None`, no values are accepted. pub open: Option<Regex>, } @@ -212,6 +213,12 @@ impl OpenScope { validation: regex.as_str().into(), }); } + } else { + log::warn!("open() command called but the plugin configuration denies calls from JavaScript; set `tauri.conf.json > plugins > shell > open` to true or a validation regex string"); + return Err(Error::Validation { + index: 0, + validation: "tauri^".to_string(), // purposefully impossible regex + }); } // The prevention of argument escaping is handled by the usage of std::process::Command::arg by
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-c9pr-q8gx-3mgpghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-31477ghsaADVISORY
- github.com/tauri-apps/plugins-workspace/commit/9cf0390a52497e273db1a1b613a0e26827aa327cghsax_refsource_MISCWEB
- github.com/tauri-apps/plugins-workspace/security/advisories/GHSA-c9pr-q8gx-3mgpghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.