{"record":{"id":"4a2675bd4e3c12c2","repo":"louislam/uptime-kuma","slug":"invalid-url-protocol-only-http-and-https-are-allo","errorCode":null,"errorMessage":"Invalid url protocol, only http and https are allowed.","messagePattern":"Invalid url protocol, only http and https are allowed\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/monitor-types/real-browser-monitor-type.js","lineNumber":264,"sourceCode":"class RealBrowserMonitorType extends MonitorType {\n    name = \"real-browser\";\n\n    /**\n     * @inheritdoc\n     */\n    async check(monitor, heartbeat, server) {\n        const browser = monitor.remote_browser\n            ? await getRemoteBrowser(monitor.remote_browser, monitor.user_id)\n            : await getBrowser();\n        const context = await browser.newContext();\n        const page = await context.newPage();\n\n        // Prevent Local File Inclusion\n        // Accept only http:// and https://\n        // https://github.com/louislam/uptime-kuma/security/advisories/GHSA-2qgm-m29m-cj2h\n        let url = new URL(monitor.url);\n        if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n            throw new Error(\"Invalid url protocol, only http and https are allowed.\");\n        }\n\n        const res = await page.goto(monitor.url, {\n            waitUntil: \"networkidle\",\n            timeout: monitor.interval * 1000 * 0.8,\n        });\n\n        // Wait for additional time before taking screenshot if configured\n        if (monitor.screenshot_delay > 0) {\n            await page.waitForTimeout(monitor.screenshot_delay);\n        }\n\n        let filename = jwt.sign(monitor.id, server.jwtSecret) + \".png\";\n\n        await page.screenshot({\n            path: path.join(Database.screenshotDir, filename),\n        });\n","sourceCodeStart":246,"sourceCodeEnd":282,"githubUrl":"https://github.com/louislam/uptime-kuma/blob/6b5ea0155793e666666745fb8d6fef1e829543a2/server/monitor-types/real-browser-monitor-type.js#L246-L282","documentation":"Before navigating, the monitor constructs new URL(monitor.url) and rejects any protocol other than http: or https:. This is an explicit Local File Inclusion (LFI) mitigation (GHSA-2qgm-m29m-cj2h): without it, a monitor URL like file:///etc/passwd could be opened by Chromium. The throw at real-browser-monitor-type.js:264 is the gate.","triggerScenarios":"monitor.url uses a non-http(s) scheme: file://, ftp://, data:, chrome://, javascript:, or a custom protocol handler. Any of these trips the protocol check immediately.","commonSituations":"User enters a file:// path expecting a local screenshot, a copy-pasted data: URL, or a mis-typed scheme. Also an adversarial input attempting LFI through the monitor.","solutions":["Use only http:// or https:// URLs in the monitor's url field.","For internal/local pages, serve them over a local HTTP server and point the monitor at that.","Strip schemes client-side before saving if integrating programmatically.","Treat any non-http(s) input as invalid in upstream form validation."],"exampleFix":"// before\nmonitor.url = \"file:///var/www/index.html\";\n// after\nmonitor.url = \"http://127.0.0.1:8080/index.html\";","handlingStrategy":"validation","validationCode":"function validateMonitorUrl(url) {\n  const u = new URL(url);              // rejects malformed URLs\n  if (u.protocol !== 'http:' && u.protocol !== 'https:') {\n    throw new Error(`Disallowed protocol ${u.protocol}; only http/https allowed`);\n  }\n  return u.toString();\n}","typeGuard":"function isHttpUrl(s) { try { const u = new URL(s); return u.protocol === 'http:' || u.protocol === 'https:'; } catch { return false; } }","tryCatchPattern":"try {\n  await realBrowserMonitor.check(monitor, heartbeat, server);\n} catch (e) {\n  if (/Invalid url protocol/.test(e.message)) {\n    // reject the monitor URL at the form layer; never auto-rewrite schemes\n  }\n  throw e;\n}","preventionTips":["Validate the URL scheme in the frontend before save.","Never accept user-supplied file:// or data:// inputs.","Treat this error as a possible LFI attempt and audit the source."],"tags":["chromium","security","url-validation","lfi"],"backgroundTag":null,"analyzedSha":"6b5ea0155793e666666745fb8d6fef1e829543a2","analyzedAt":"2026-08-12T23:42:12.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}