Budibase/budibase · error
Invalid URL.
Error message
Invalid URL.
What it means
parseUrl() in the SSRF-safe outbound fetch helper wraps `new URL(url)` in try/catch and throws a plain Error('Invalid URL.') when the WHATWG URL parser rejects the input (malformed or non-absolute URL). Every outbound request through this helper validates its target URL first, so any fetch with an unparseable URL fails here.
Source
Thrown at packages/backend-core/src/utils/outboundFetch.ts:21
import { isBlacklisted, resolveAddress } from "../blacklist"
import fetch, { Headers, RequestInit, Response } from "node-fetch"
import type { LookupFunction } from "net"
const MAX_REDIRECTS = 5
const ALLOWED_PROTOCOLS = new Set(["http:", "https:"])
const SENSITIVE_REDIRECT_HEADERS = [
"authorization",
"cookie",
"cookie2",
"proxy-authorization",
]
function parseUrl(url: string): URL {
let parsed: URL
try {
parsed = new URL(url)
} catch {
throw new Error("Invalid URL.")
}
if (!ALLOWED_PROTOCOLS.has(parsed.protocol)) {
throw new Error("Only HTTP(S) URLs are allowed.")
}
if (parsed.username || parsed.password) {
throw new Error("URL must not include credentials.")
}
return parsed
}
function isRedirect(status: number): boolean {
return [301, 302, 303, 307, 308].includes(status)
}
async function resolveSafePinnedIp(url: string): Promise<string> {View on GitHub (pinned to a81a902e9a)
Solutions
- Prepend the scheme: use absolute URLs like "https://example.com/path"
- Trim and validate the URL string before calling - encode/escape any user-supplied segments
- Store normalized URLs at write time (e.g. new URL(input).toString()) so bad values never reach the fetch
- Add upstream form validation requiring a full absolute URL
Example fix
// before
await outboundFetch("example.com/api") // Invalid URL.
// after
await outboundFetch("https://example.com/api") Defensive patterns
Strategy: validation
Validate before calling
// validate the URL before fetching
function isParsableUrl(u: string): boolean {
try {
const parsed = new URL(u)
return parsed.protocol === "http:" || parsed.protocol === "https:"
} catch {
return false
}
}
if (!isParsableUrl(url)) throw new Error("Provide an absolute http(s) URL") Type guard
function isAbsoluteHttpUrl(u: string): u is string {
try {
return new URL(u).protocol.startsWith("http")
} catch {
return false
}
} Try / catch
try {
const res = await outboundFetch(url)
} catch (e: any) {
if (e?.message === "Invalid URL.") {
// normalize: trim, prepend https:// if scheme missing, then retry once
} else throw e
} Prevention
- Always store absolute URLs with scheme (https://...)
- Trim whitespace from user input before persisting URLs
- Normalize with new URL(input).toString() at write time
- Require full URLs in forms rather than host/path pairs
When it happens
Trigger: Calling outboundFetch functions (fetch/get etc.) with a URL like "example.com/api" (missing scheme), an empty string, whitespace, or other input that `new URL()` cannot parse.
Common situations: User-supplied webhook/query URLs stored without a scheme; template-interpolated URLs producing "https://undefined/..."-adjacent garbage; config values missing "https://" prefix; trailing spaces from form input.
Related errors
- Only HTTP(S) URLs are allowed.
- Invalid Github URL
- The plugin origin must be from Github
- Invalid NPM URL
- The plugin origin must be from NPM
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/0ee75f7be8953122.
Report an issue: GitHub.