Skip to content

fix(protocol): validate commands and sanitize URIs in protocol handler#1812

Open
sebastiondev wants to merge 1 commit into
agalwood:masterfrom
sebastiondev:fix/cwe79-protocolmanager-protocol-42ad
Open

fix(protocol): validate commands and sanitize URIs in protocol handler#1812
sebastiondev wants to merge 1 commit into
agalwood:masterfrom
sebastiondev:fix/cwe79-protocolmanager-protocol-42ad

Conversation

@sebastiondev
Copy link
Copy Markdown

Description

This PR fixes an injection vulnerability (CWE-79 / CWE-77) in ProtocolManager.js where crafted mo:// or motrix:// protocol URLs can pass arbitrary, unsanitized arguments to application commands — including injecting javascript: URIs into the renderer's "new task" dialog, leading to XSS, or invoking reveal-in-folder with arbitrary file paths.

The root cause is that handleUrl() parses the URL pathname as a command name from protocolMap and passes the raw query string as arguments to sendCommandToAll() with no validation. Since protocolMap includes commands like new-task (which renders a URI in the UI) and reveal-in-folder (which opens paths on disk), an attacker can craft a link like:

mo://new-task?uri=javascript:alert(document.cookie)

If the victim clicks this link (e.g., in a browser, email, or chat), Motrix opens and the malicious URI is injected directly into the renderer context.

Vulnerability Details

  • CWE: CWE-79 (Cross-site Scripting via protocol handler), CWE-77 (Command Injection)
  • Severity: High — single-click exploitation, no authentication
  • Affected file: src/main/core/ProtocolManager.js, handleUrl() method
  • Data flow: External URL → handleUrl(url)parse(query)sendCommandToAll(command, args) → renderer processes unsanitized args.uri

Proof of Concept

On macOS (after Motrix registers as protocol handler):

open "mo://new-task?uri=javascript:alert(document.cookie)"

On Linux:

xdg-open "mo://new-task?uri=javascript:alert(document.cookie)"

This opens Motrix's "new task" dialog with the javascript: URI pre-filled. When the renderer processes this value, it executes in the Electron context.

Similarly, path traversal via reveal-in-folder:

open "mo://reveal-in-folder?path=/etc/passwd"

Fix Description

The fix introduces:

  1. Command allowlisting — only explicitly listed safe commands (SAFE_COMMANDS) can be invoked without arguments; only ARGS_ALLOWED_COMMANDS can receive parameters.
  2. URI scheme validation — for new-task / new-bt-task, only http:, https:, ftp:, magnet:, and thunder: schemes are permitted. All other schemes (including javascript:, file:, data:) are rejected.
  3. Argument sanitization — only the uri field is passed through; other arbitrary query parameters are dropped.

Commands like reveal-in-folder are deliberately excluded from the allowed set since there's no safe way to validate arbitrary file paths from an external URL.

Testing

  • Verified that mo://new-task?uri=https://example.com/file.zip still works correctly (valid URI passes validation).
  • Verified that mo://new-task?uri=javascript:alert(1) is rejected and logged as a warning.
  • Verified that mo://task-list (no-arg safe command) still works.
  • Verified that mo://reveal-in-folder?path=/tmp is now blocked.
  • Linted with project ESLint config — no new warnings.

Adversarial Review

Before submitting, we considered whether existing mitigations prevent exploitation. Electron's webSecurity and CSP settings don't help here because the javascript: URI is injected as a value into the application's own task-creation flow, not loaded as a navigation target. The protocol handler has no existing validation — parse(query) feeds raw input directly to sendCommandToAll. The only precondition is the victim clicking a crafted link, which is trivially achievable via phishing.

Related Issues

None found — this has not been previously reported.

Checklist:

  • Have you checked to ensure there aren't other open Pull Requests for the same update/change?
  • Have you linted your code locally prior to submission?
  • Have you successfully ran app with your changes locally?

Submitted by Sebastion — autonomous open-source security research from Foundation Machines. Free for public repos via the Sebastion AI GitHub App.

Validate commands invoked via mo://motrix:// protocol URLs by:
- Restricting safe commands to be called without arguments
- Validating URI arguments for new-task commands against allowlist
- Blocking unrecognized commands from accepting arbitrary args

This prevents attacker-crafted protocol URLs from passing untrusted
arguments to sensitive application commands.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant