{"record":{"id":"36d434f46afb92e2","repo":"nexu-io/open-design","slug":"invalid-brand-asset-url-string-url","errorCode":null,"errorMessage":"invalid brand asset url: ${String(url)}","messagePattern":"invalid brand asset url: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/brands/safe-fetch.ts","lineNumber":62,"sourceCode":"  //   IPv4 link-local/metadata (169.254), IPv4 multicast (>=224), `::`,\n  //   IPv6 link-local (fe80::/10) and ULA (fc00::/7).\n  return isLoopbackApiHost(h) || isBlockedExternalApiHostname(h);\n}\n\nfunction isIpLiteral(host: string): boolean {\n  return /^\\d{1,3}(?:\\.\\d{1,3}){3}$/.test(host) || host.includes(':');\n}\n\n/**\n * Throw unless `url` is an http(s) URL whose host is a public address — checked\n * both as the literal host and, for a hostname, against every DNS answer.\n */\nexport async function assertPublicBrandUrl(url: string): Promise<void> {\n  let parsed: URL;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`invalid brand asset url: ${String(url)}`);\n  }\n  if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n    throw new Error(`unsupported brand asset protocol: ${parsed.protocol}`);\n  }\n  const host = parsed.hostname.replace(/^\\[/, '').replace(/\\]$/, '').toLowerCase();\n  if (isNonPublicHost(host)) {\n    throw new Error(`blocked non-public brand asset host: ${host}`);\n  }\n  if (!isIpLiteral(host)) {\n    let addresses: Array<{ address: string }>;\n    try {\n      addresses = await dnsPromises.lookup(host, { all: true });\n    } catch {\n      // Let the actual fetch surface a resolution failure rather than masking it.\n      return;\n    }\n    for (const { address } of addresses) {\n      if (isNonPublicHost(String(address))) {","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/brands/safe-fetch.ts#L44-L80","documentation":"Thrown by assertPublicBrandUrl when `new URL(url)` raises — the brand asset URL cannot be parsed at all. assertPublicBrandUrl is the SSRF pre-check installed in front of every brand outbound fetch (logo/imagery/seed/font fallbacks, prefetch, library route), so a malformed URL aborts before any network call.","triggerScenarios":"fetchExternalBrandAsset is called with an empty string, a URL missing its scheme ('example.com/x.png'), a URL with whitespace/control chars, or garbage scraped from a page (e.g. an href of 'javascript:...' that bypassed earlier filtering, or undefined coerced to the string 'undefined').","commonSituations":"Page-scraping fallbacks encounter hrefs that look URL-ish but are not absolute; an LLM-produced brand.json lists a logo URL with a typo; a connector hands a relative href straight to the fetcher without resolving it against the page base.","solutions":["Resolve scraped hrefs against the page base URL before calling fetchExternalBrandAsset: new URL(href, pageUrl).toString().","Filter candidates through a URL parse pre-check and skip unparseable ones rather than aborting the whole extraction.","If the URL is user-supplied, require an absolute http(s) string at the API boundary and 400 the request otherwise.","Wrap fetchExternalBrandAsset in try/catch per-asset so one bad URL does not kill the whole brand build."],"exampleFix":"// before\nconst res = await fetchExternalBrandAsset(rawHref);\n// after\nlet abs;\ntry { abs = new URL(rawHref, pageUrl).toString(); } catch { continue; }\nconst res = await fetchExternalBrandAsset(abs);","handlingStrategy":"validation","validationCode":"function parseOrNull(url, base) {\n  try { return new URL(url, base); } catch { return null; }\n}\n// skip unparseable hrefs instead of forwarding them\nconst abs = parseOrNull(rawHref, pageUrl);\nif (!abs) continue;","typeGuard":"const isParsableUrl = (u: unknown, base?: string): u is string => {\n  if (typeof u !== 'string' || !u) return false;\n  try { new URL(u, base); return true; } catch { return false; }\n};","tryCatchPattern":"try {\n  await fetchExternalBrandAsset(absUrl);\n} catch (e) {\n  if (String(e.message).startsWith('invalid brand asset url')) {\n    // skip this asset, keep extracting others\n    continue;\n  }\n  throw e;\n}","preventionTips":["Resolve scraped hrefs against the page base URL before forwarding.","Filter out non-http(s) and unparseable hrefs at the scraper.","Wrap each asset fetch in try/catch so one bad URL does not abort extraction."],"tags":["ssrf","url-validation","brand","network","safe-fetch"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}