Budibase/budibase · error · HTTPError

Import url must not contain credentials

Error message

Import url must not contain credentials

What it means

parseImportUrl throws this HTTPError(400) when the URL embeds user credentials (user:pass@host), which Budibase disallows to prevent credential leakage into stored import sources and SSRF-style misuse.

Source

Thrown at packages/server/src/api/controllers/query/import/index.ts:87

  crypto.createHash("sha512").update(JSON.stringify(input)).digest("hex")

const buildCacheKey = (input: ImporterInput) =>
  `openapiSpecs:${stringToHashKey(JSON.stringify("data" in input ? input.data : input.url))}`

function parseImportUrl(url: string): URL {
  let parsed: URL
  try {
    parsed = new URL(url)
  } catch {
    throw new HTTPError("Invalid import url", 400)
  }

  if (!ALLOWED_IMPORT_PROTOCOLS.has(parsed.protocol)) {
    throw new HTTPError("Only HTTP(S) URLs are allowed for query import", 400)
  }

  if (parsed.username || parsed.password) {
    throw new HTTPError("Import url must not contain credentials", 400)
  }

  return parsed
}

async function fetchFromUrl(url: string): Promise<string> {
  try {
    // validate protocol / credentials up front for clear 400 errors
    parseImportUrl(url)
    // fetchWithBlacklist resolves and validates the target, pins the request to
    // the validated IP (preventing DNS rebinding between validation and the
    // actual connection) and safely follows redirects, re-validating each hop.
    const response = await utils.fetchWithBlacklist(url)

    if (!response.ok) {
      throw new HTTPError(
        `Failed to fetch import data (status ${response.status})`,
        response.status

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Remove the username/password from the URL and use headers for authentication instead
  2. Use API-key headers or a proxy that injects credentials server-side
  3. Configure the datasource auth separately from the import URL

Example fix

// before
const url = 'https://admin:s3cret@api.example.com/data.json'
// after
const url = 'https://api.example.com/data.json' // pass auth via headers
Defensive patterns

Strategy: validation

Validate before calling

const u = new URL(url)
if (u.username || u.password) throw new Error('Remove credentials from the URL; supply auth via headers instead')

Type guard

function isCredentialFreeUrl(url: string): boolean {
  try { const u = new URL(url); return !u.username && !u.password } catch { return false }
}

Try / catch

try {
  await importSource(url)
} catch (err) {
  if (err instanceof HTTPError && err.message.includes('must not contain credentials')) {
    // strip userinfo and configure authentication via headers/datasource config
  }
}

Prevention

When it happens

Trigger: Import URLs like https://user:password@api.example.com/data.json where basic-auth credentials are embedded in the URL userinfo component.

Common situations: Copying URLs from tools that embed basic auth in the host part; API providers documenting credential-in-URL access; secrets pasted into the URL field.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/e9e802eb9b3230a6. Report an issue: GitHub.