Repository navigation
Conversation
Links using a non-web scheme (discord://, zoommtg://, mailto:, tel:, ...) do nothing when clicked. WebKit cannot load those schemes and silently drops the navigation, so the link appears dead. This affects every 'open in app' flow: joining a Discord server, starting a Zoom meeting, opening a mail client from a mailto: link. Non-web schemes are now handed to NSWorkspace, which launches the registered application, and the navigation is cancelled.
|
| if let url = navigationAction.request.url, | ||
| let scheme = url.scheme?.lowercased(), | ||
| !Self.webSchemes.contains(scheme) | ||
| { | ||
| // WebKit silently drops unknown schemes, so the link looks dead. | ||
| // Hand it to the system, which opens the registered app. | ||
| NSWorkspace.shared.open(url) |
There was a problem hiding this comment.
Unprompted external app launches
A page can initiate a custom-scheme navigation through a script, redirect, or subframe. Every WebKit policy action reaches this delegate with only its request and modifier flags, so this branch cannot verify a user gesture or main-frame link before passing the URL to NSWorkspace.open. Untrusted content can therefore launch a registered application and send it attacker-controlled URL parameters without user interaction. Restrict this handoff to explicit user-activated navigation and retain the WebKit action metadata needed to enforce that restriction.
How this was verified: Every WebKit policy action is reduced to its request and modifier flags before this unconditional non-web-scheme branch launches the registered handler.
Problem
Clicking a link with a non-web scheme does nothing.
discord://,zoommtg://,mailto:,tel:are all silently dropped: WebKit cannot load them, andTabBrowserPageDelegatereturns.allowfor everything that is not a cmd-click, so the navigation dies with no feedback.Real-world impact: opening a Discord invite from a web page never launches the app (this is how I hit it, from the invite link in this project's own README), Zoom meeting links do nothing, and
mailto:links never reach the mail client.Change
decidePolicyFornow inspects the scheme first. Anything outside the set WebKit handles (http,https,about,data,blob,file,javascript) is passed toNSWorkspace.shared.open(_:)and the navigation is cancelled, which is the standard behavior for a macOS browser.Testing
Built Release on macOS 26.2.
discord://invite link: before nothing happened, after Discord.app opens.NSWorkspace.urlForApplication(toOpen:):discord://resolves to Discord.app,mailto:to the default mail client.http(s)navigation and cmd-click open-in-new-tab are unaffected, since the new branch only triggers for schemes outside the web set.