From 27df680932132ccdbc2a6c8589f9b0de950a16e2 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Sat, 21 Mar 2026 22:51:27 +0100 Subject: [PATCH] validate URL scheme before opening in url_opener Restrict open_url() to http:// and https:// schemes only. Malformed or unexpected URLs from the API (e.g. file://, javascript:, custom schemes) are now rejected with a warning log instead of being passed through to xdg-open or the XDG Desktop Portal. Closes #21 --- forgewatch/url_opener.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/forgewatch/url_opener.py b/forgewatch/url_opener.py index 7277ba3..859e061 100644 --- a/forgewatch/url_opener.py +++ b/forgewatch/url_opener.py @@ -10,6 +10,8 @@ logger = logging.getLogger(__name__) +_ALLOWED_SCHEMES = frozenset(("http", "https")) + # XDG Desktop Portal D-Bus coordinates. The portal allows sandboxed # processes (systemd services, Flatpak, Snap) to open URLs in the @@ -22,10 +24,20 @@ async def open_url(url: str) -> None: """Open *url* in the default browser. + Only ``http`` and ``https`` URLs are accepted. Any other scheme is + rejected with a warning to prevent opening arbitrary protocols via + ``xdg-open`` or the XDG Desktop Portal. + Tries the XDG Desktop Portal first (works from sandboxed systemd services), then falls back to ``xdg-open`` for environments where the portal is unavailable (e.g. minimal window managers). """ + from urllib.parse import urlparse + + parsed = urlparse(url) + if parsed.scheme not in _ALLOWED_SCHEMES: + logger.warning("Rejected URL with disallowed scheme %r: %s", parsed.scheme, url) + return if await _open_url_portal(url): return await _open_url_xdg(url)