different-ai/openwork · error
External URL protocol "${parsed.protocol}" is not allowed.
Error message
External URL protocol "${parsed.protocol}" is not allowed. What it means
After the URL parses, assertDesktopWebUrl enforces an allow-list of protocols: only http: and https: may be opened externally. Anything else — file:, javascript:, data:, custom schemes — is rejected with a message naming the offending protocol, blocking protocol-handler abuse (e.g. opening local files or arbitrary app handlers via crafted links).
Source
Thrown at apps/app/src/app/lib/desktop.ts:478
}
return desktopFetchThroughMain(input, init, {
agentContextDiagnosticsDeadlineAtMs: deadlineAtMs,
});
}
// ---------------------------------------------------------------------------
// Convenience wrappers
// ---------------------------------------------------------------------------
export function assertDesktopWebUrl(url: string): string {
let parsed: URL;
try {
parsed = new URL(url);
} catch {
throw new Error("Only valid web links can be opened externally.");
}
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
throw new Error(`External URL protocol "${parsed.protocol}" is not allowed.`);
}
return parsed.toString();
}
export async function openDesktopUrl(url: string): Promise<void> {
const safeUrl = assertDesktopWebUrl(url);
const openExternal = window.__OPENWORK_ELECTRON__?.shell?.openExternal;
if (openExternal) {
const result = await openExternal(safeUrl);
if (result && result.ok === false) {
throw new Error(result.error ?? "Failed to open browser");
}
return;
}
if (typeof window !== "undefined") {
window.open(safeUrl, "_blank", "noopener,noreferrer");
}
}View on GitHub (pinned to 2b7df46e8a)
Solutions
- Convert non-web inputs to a permitted form first: local files should use openDesktopPath/revealDesktopItemInDir, not openDesktopUrl.
- Normalize the scheme: if the target is meant to be a website but uses a wrong scheme, rewrite it to https:// before calling.
- If a custom scheme genuinely must open, add an explicit allow-listed code path (e.g. shell.openExternal via the Electron bridge) rather than bypassing the guard silently.
- Sanitize dynamic link sources (chat messages, imported configs) to reject or rewrite non-http(s) URLs at ingestion.
Example fix
// before
await openDesktopUrl("file:///tmp/report.pdf");
// after
await openDesktopPath("/tmp/report.pdf"); // opens/locally reveals instead Defensive patterns
Strategy: validation
Validate before calling
const parsed = new URL(url);
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
throw new Error(`Refusing to open ${parsed.protocol} link externally`);
} Type guard
function isWebUrl(u: URL): boolean {
return u.protocol === "http:" || u.protocol === "https:";
} Try / catch
try {
await openDesktopUrl(link);
} catch (err) {
if (err instanceof Error && err.message.includes("is not allowed")) {
showToast("Only web (http/https) links can be opened in the browser");
} else { throw err; }
} Prevention
- Route local files to openDesktopPath/revealDesktopItemInDir, never openDesktopUrl.
- Sanitize dynamic link content (chat, markdown, imports) to http(s) only at ingestion.
- Never attempt to open blob:, data:, or custom app schemes through this helper.
- Keep an explicit, reviewed allow-list if custom schemes ever need support.
When it happens
Trigger: openDesktopUrl / safeUrl / waitForManagedMcpAuthorization receiving a URL whose scheme is not http/https, e.g. `file:///Users/x/doc.pdf`, `javascript:void(0)`, `data:text/html,...`, or a custom app scheme like `slack://` or `vscode://` passed to the external opener.
Common situations: Attempting to reveal a local file path via openDesktopUrl instead of openDesktopPath; rendering attacker-influenced link content (markdown/chat) and opening it directly; passing internal app schemes or workspace:// URIs that the desktop bridge does not allow; tests constructing `about:blank` or `blob:` URLs.
Related errors
- Only valid web links can be opened externally.
- managed MCP egress requires HTTPS
- Electron desktop helper is unavailable: ${command}
- Failed to open browser
- ${result}
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/76ad5a868dd7184a.
Report an issue: GitHub.