Agent Wranglers

DSK-12Recommended

Open outside links only after checking the address

Block navigation and new windows away from the app's own pages. Hand a link to the system browser only when its scheme is https: or mailto:.

How to do it

Passing any address to shell.openExternal or the system opener can start other programs through schemes such as file: or smb:. Catch will-navigate and the window open handler, and deny by default. When the app registers its own scheme, such as ledgerly://, every incoming link is untrusted input. Check it as check the sender and content of every message to the main process does for messages.

Examples

JavaScript example

const ALLOWED_SCHEMES = new Set(['https:', 'mailto:']);

app.on('web-contents-created', (_, contents) => {
  contents.on('will-navigate', event => event.preventDefault());
  contents.setWindowOpenHandler(({ url }) => {
    if (ALLOWED_SCHEMES.has(new URL(url).protocol)) shell.openExternal(url);
    return { action: 'deny' };
  });
});

Plain text example

const ALLOWED_SCHEMES: [&str; 2] = ["https", "mailto"];

fn open_outside(app: &tauri::AppHandle, raw: &str) -> Result<(), String> {
    let url = url::Url::parse(raw).map_err(|_| "bad link")?;
    if !ALLOWED_SCHEMES.contains(&url.scheme()) {
        return Err("scheme not allowed".into());
    }
    app.opener().open_url(url.as_str(), None::<&str>).map_err(|e| e.to_string())
}

How to check

A test clicks links to file:///etc/passwd, smb://example.com/share and https://example.com. Only the last one opens, and only in the system browser. The app window stays on its own page.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/desktop-apps/web-code-inside-desktop-apps/safe-external-links">Agent Wranglers desktop apps, extensions and CLIs playbook</a>. In code you write, add a comment next to it with the same link.