Budibase/budibase · error
URL is blocked or could not be resolved safely.
Error message
URL is blocked or could not be resolved safely.
What it means
outboundFetch.ts performs SSRF protection before every request: resolveSafePinnedIp parses the URL, resolves the hostname via the blacklist module's DNS resolver, and requires at least one resolved address. This error means DNS resolution returned no addresses for the hostname, so the library cannot pin a safe IP and refuses to fetch.
Source
Thrown at packages/backend-core/src/utils/outboundFetch.ts:43
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> {
const parsed = parseUrl(url)
const addresses = await resolveAddress(parsed.hostname)
if (addresses.length === 0) {
throw new Error("URL is blocked or could not be resolved safely.")
}
for (const address of addresses) {
if (await isBlacklisted(address)) {
throw new Error("URL is blocked or could not be resolved safely.")
}
}
return addresses[0]
}
// Always pin to the first resolved IP address to avoid DNS rebinding attacks.
export function createPinnedLookup(ip: string): LookupFunction {
const family = ip.includes(":") ? 6 : 4
return (_hostname, _options, callback) => {
if (typeof _options === "object" && _options?.all) {
callback(null, [{ address: ip, family }])
returnView on GitHub (pinned to a81a902e9a)
Solutions
- Verify the hostname with `nslookup <host>` or `dig <host>` from the same environment to confirm DNS actually resolves.
- Fix the URL (typos, removed domains, trailing dots/scheme issues) at the source where it is configured.
- Fix container/environment DNS configuration (resolv.conf, CoreDNS, VPC DNS) so the resolver can return A/AAAA records.
- If the domain is genuinely internal, ensure the process runs where that internal DNS is reachable.
Example fix
// before
await fetchWithBlacklist("https://api.exmaple.com/data")
// after (typo corrected, verified resolvable)
await fetchWithBlacklist("https://api.example.com/data") Defensive patterns
Strategy: validation
Validate before calling
let parsed: URL
try { parsed = new URL(url) } catch { throw new Error("Invalid URL") }
if (!/^https?:$/.test(parsed.protocol)) throw new Error("Only HTTP(S)")
if (parsed.hostname === "localhost") throw new Error("Blocked host")
// then confirm DNS before fetching:
const addrs = await dns.promises.lookup(parsed.hostname, { all: true })
if (addrs.length === 0) throw new Error("Hostname does not resolve") Type guard
const isHttpUrl = (url: string): url is string => {
try {
const parsed = new URL(url)
return parsed.protocol === "http:" || parsed.protocol === "https:"
} catch {
return false
}
} Try / catch
try {
const res = await fetchWithBlacklist(url)
} catch (err) {
if (err instanceof Error && err.message.includes("blocked or could not be resolved")) {
// surface a "hostname unreachable / not allowed" user-facing message
} else throw err
} Prevention
- Validate hostnames resolve (dns.lookup) before storing webhook/query URLs.
- Reject localhost/internal hostnames at configuration time.
- Fix container DNS before relying on external fetches.
When it happens
Trigger: Calling fetchWithBlacklist (via pinnedIp/resolveSafePinnedIp) with a URL whose hostname fails to resolve: empty resolveAddress() result due to a nonexistent domain, broken DNS in the environment, or a hostname that the internal resolver refuses.
Common situations: Typo'd or deleted hostnames in user-supplied webhook/query URLs; containers with no working DNS resolver (/etc/resolv.conf missing or pointing at an unreachable resolver); private hostnames only resolvable via custom DNS the Node process doesn't use.
Related errors
- Failed to fetch import data - ${message}
- IMAP host is blocked or could not be resolved safely
- Invalid SharePoint pagination URL
- Error getting account by tenantId ${tenantId}
- Error getting status
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/258930628fd28e56.
Report an issue: GitHub.