Skip to content

Windows command injection in Tauri open_url IPC (cmd /c start) — user-assisted desktop RCE

High
koala73 published GHSA-2x6r-qq54-mmhr Jul 4, 2026

Package

koala73/worldmonitor

Affected versions

<= 2.8.0 (main @ commit 16d0a12e) — Windows desktop builds only

Patched versions

None

Description

Summary

On Windows desktop builds, the Tauri IPC command open_url routes an attacker-influenceable URL through cmd.exe (cmd /c start "" <url>) without neutralizing shell metacharacters. Rust's std only quotes an argument that contains whitespace/quotes; a URL has none, so it is emitted unquoted and cmd.exe treats & as a command separator. A malicious link rendered in a trusted app window becomes arbitrary command execution in the victim's user context after a single click (CWE-78, OS Command Injection). macOS and Linux are unaffected.

Details

Sink. open_in_shell (src-tauri/src/main.rs:522-527, Windows branch) runs:

Command::new("cmd").args(["/c", "start", "", arg])

Rust's std command builder wraps an argument in quotes only when it contains a space, tab, or quote. A URL such as https://example.com/?x=1&calc contains none (spaces would be %20), so it lands on the command line unquoted. cmd.exe then parses the unquoted & as a statement separator and executes the trailing token(s) as separate commands — e.g. &calc&whoami.

Taint path (attacker → RCE):

  1. An attacker-controlled <link> in any aggregated RSS/news feed is rendered as an anchor inside a trusted app window.
  2. The capture-phase click handler (src/app/event-handlers.ts:690-704) reads anchor.href, runs new URL() (scheme/origin checks only — no metacharacter stripping), and calls invokeTauri('open_url', { url }) (:704).
  3. open_url (src-tauri/src/main.rs:548-561) runs require_trusted_window (validates the window, not the URL) and Url::parse (validates only the scheme), then calls open_in_shell(parsed.as_str()).

Why the guards fail. require_trusted_window checks the origin window, which is legitimately the trusted main window carrying tainted feed content. Url::parse enforces https/http-localhost but does not remove & | < > ^ ( ) — all legal in a URL query/fragment. macOS (open) and Linux (xdg-open) exec a single argv with no shell, so only Windows is affected.

PoC

On a Windows build, in the main window devtools console:

window.__TAURI_INTERNALS__.invoke('open_url', { url: 'https://example.com/?x=1&calc' })
// -> calc.exe launches

Full chain: point the app at a feed whose item link is that URL, then click the headline.

Modeled command-line parse (faithful model of the documented Windows cmd.exe behavior; included as poc-F2-tauri-cmd-injection.mjs):

built command line: cmd /c start "" https://example.com/?a=1&calc&whoami
cmd.exe runs 3 command(s): ["cmd /c start \"\" https://example.com/?a=1", "calc", "whoami"]
>>> INJECTED: ["calc", "whoami"]

Impact

Arbitrary command execution in the victim's user context on Windows desktop builds, triggered by clicking a malicious headline/link that the app renders from aggregated feed content. Full confidentiality/integrity/availability impact within that user account (file theft, persistence, further payload download). Requires user interaction (a click) and is Windows-only, hence High rather than Critical.

Remediation

Never route URLs through cmd.exe. Open links via ShellExecuteW, the open/opener crate, or tauri-plugin-opener, or spawn the browser binary directly with an argv vector (no shell interpretation). A tested unified-diff patch (F2-tauri-cmd-injection.patch) is available in the coordinated-disclosure package.


Maintainer validation (2026-07-04): Valid historically, but no longer live on current origin/main. Tauri open_url no longer shells through cmd.exe on Windows; it uses opener/ShellExecuteW-style handling, and src-tauri/open-url-safety.test.mjs asserts cmd.exe is not spawned. Published advisories cannot be closed through the GitHub API, so this is marked in-description as fixed/no longer active.

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
Required
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

CVE ID

No known CVE

Weaknesses

Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component. Learn more on MITRE.

Credits