Symptoms
Ctrl+clicking a URL (auto-detected or OSC 8 hyperlink) in a Limux pane on Wayland/Plasma 6:
- The URL is opened in the default browser, but the browser window is not brought to the foreground. Konsole, by contrast, raises the window correctly.
- In some configurations (AppImage with a stale Firefox instance, or
gio failing to dispatch silently), Ctrl+click appears to do nothing at all.
Root cause
open_url_in_external_browser in rust/limux-host-linux/src/pane.rs calls:
gtk::gio::AppInfo::launch_default_for_uri(url, None::<>k::gio::AppLaunchContext>)
Passing None for the AppLaunchContext means GIO does not generate an xdg-activation token, so under Wayland focus-stealing prevention the target window has no permission to raise itself. KIO (used by Konsole) wires this token via its own launch path.
Proposed fix
-
Activation token. Pass Some(&display.app_launch_context()) from the default GdkDisplay, so GIO emits the xdg-activation token. Window raise works under Wayland.
-
Fallback to xdg-open (with a small reaper thread to avoid zombie children) if gio returns Err — for AppImage / sandboxed contexts where the bundled GIO can't dispatch.
-
Strict URI scheme allow-list. Validate the scheme against a hard-coded list (http / https / mailto), case-insensitive per RFC 3986 §3.1. Schemes outside the list are refused before any handler is invoked.
How we arrived at this allow-list
The threat model is hostile terminal output: anything that ends up in a pane's scrollback can craft an OSC 8 hyperlink, and clicking it must not lead to code execution. A cat of a malicious file, a compromised SSH session, or a colleague's repro that includes a crafted link should be safe to Ctrl+click without triggering RCE.
The starting "obvious" list was http/https/mailto/ftp/ftps/file. After reviewing the literature on URI-handler attacks we trimmed it down:
| Scheme |
Verdict |
Why |
http://, https:// |
✅ keep |
Web navigation, sandboxed by the browser. |
mailto: |
✅ keep |
Email client takes care of the rest; low attack surface. |
javascript:, vbscript:, data: |
❌ block |
Classic XSS / scripting sinks. Gitea blocks these unconditionally even when other schemes are allowed (gitea#25960). |
file:// |
❌ drop |
Local file handler can execute .desktop files, scripts, binaries. A hostile cat of a crafted file is RCE (positive.security/blog/url-open-rce). |
ftp://, ftps://, smb://, nfs://, dav://, davs://, sftp:// |
❌ drop |
All auto-mount via gvfs and let an attacker execute binaries from the mounted share. Single-click RCE in the Positive Security writeup. |
Custom URIs (vscode://, slack://, obsidian://, cursor://, …) |
❌ drop |
App-specific URI handlers have a long CVE history (VS Code, Slack, Zoom, ...). We don't second-guess that surface area; users who need them can open via their own shell. |
Windows-relays (ms-msdt:, search-ms:) |
❌ drop |
Follina (CVE-2022-30190) and related. Mostly irrelevant on Linux but Wine/Proton could reroute. |
We also drop syntactically-malformed inputs: bare paths, leading whitespace, missing ://, etc. RFC 3986 §3.1 case-insensitivity is honoured (HTTPS://example.com is valid and accepted).
The bar to add a scheme to the allow-list later: a clear use case, an audit of the handler's attack surface, and ideally an opt-in switch in the limux config rather than a default.
References
Symptoms
Ctrl+clicking a URL (auto-detected or OSC 8 hyperlink) in a Limux pane on Wayland/Plasma 6:
giofailing to dispatch silently), Ctrl+click appears to do nothing at all.Root cause
open_url_in_external_browserinrust/limux-host-linux/src/pane.rscalls:Passing
Nonefor theAppLaunchContextmeans GIO does not generate an xdg-activation token, so under Wayland focus-stealing prevention the target window has no permission to raise itself. KIO (used by Konsole) wires this token via its own launch path.Proposed fix
Activation token. Pass
Some(&display.app_launch_context())from the defaultGdkDisplay, so GIO emits the xdg-activation token. Window raise works under Wayland.Fallback to
xdg-open(with a small reaper thread to avoid zombie children) ifgioreturnsErr— for AppImage / sandboxed contexts where the bundled GIO can't dispatch.Strict URI scheme allow-list. Validate the scheme against a hard-coded list (
http/https/mailto), case-insensitive per RFC 3986 §3.1. Schemes outside the list are refused before any handler is invoked.How we arrived at this allow-list
The threat model is hostile terminal output: anything that ends up in a pane's scrollback can craft an OSC 8 hyperlink, and clicking it must not lead to code execution. A
catof a malicious file, a compromised SSH session, or a colleague's repro that includes a crafted link should be safe to Ctrl+click without triggering RCE.The starting "obvious" list was
http/https/mailto/ftp/ftps/file. After reviewing the literature on URI-handler attacks we trimmed it down:http://,https://mailto:javascript:,vbscript:,data:file://.desktopfiles, scripts, binaries. A hostilecatof a crafted file is RCE (positive.security/blog/url-open-rce).ftp://,ftps://,smb://,nfs://,dav://,davs://,sftp://vscode://,slack://,obsidian://,cursor://, …)ms-msdt:,search-ms:)We also drop syntactically-malformed inputs: bare paths, leading whitespace, missing
://, etc. RFC 3986 §3.1 case-insensitivity is honoured (HTTPS://example.comis valid and accepted).The bar to add a scheme to the allow-list later: a clear use case, an audit of the handler's attack surface, and ideally an opt-in switch in the limux config rather than a default.
References
javascript/vbscript/dataURL schemes