{"record":{"id":"7f8a80765fc731ed","repo":"santifer/career-ops","slug":"a16z-speedrun-talent-untrusted-hostname-parsed","errorCode":null,"errorMessage":"a16z-speedrun-talent: untrusted hostname \"${parsed.hostname}\" — must be ${TRUSTED_HOST}","messagePattern":"a16z-speedrun-talent: untrusted hostname \"(.+?)\" — must be (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/a16z-speedrun-talent.mjs","lineNumber":49,"sourceCode":"// feed's reported total_pages (or, when the feed omits it, a short page), so\n// on an honest feed the cap costs nothing and full-board sweeps keep working\n// as the board grows.\n// It only bites a misbehaving feed or an absurd max_pages entry — so it\n// sits well above plausible board size (~353 pages / ~17.6k jobs as of\n// 2026-08), same policy as workday.mjs's cap.\nconst MAX_PAGES_CAP = 1000;\n\n/** @param {string} url */\nfunction assertFeedUrl(url) {\n  let parsed;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`a16z-speedrun-talent: invalid URL: ${url}`);\n  }\n  if (parsed.protocol !== 'https:') throw new Error(`a16z-speedrun-talent: URL must use HTTPS: ${url}`);\n  if (parsed.hostname !== TRUSTED_HOST) {\n    throw new Error(`a16z-speedrun-talent: untrusted hostname \"${parsed.hostname}\" — must be ${TRUSTED_HOST}`);\n  }\n  return url;\n}\n\n/** Resolve the page cap: a positive integer `max_pages` on the entry, capped. */\nfunction resolveMaxPages(entry) {\n  const v = entry?.max_pages;\n  if (Number.isInteger(v) && v > 0) return Math.min(v, MAX_PAGES_CAP);\n  return DEFAULT_MAX_PAGES;\n}\n\n/** Optional server-side query: `q:` on the entry, else joined `keywords:`. */\nfunction resolveQuery(entry) {\n  if (typeof entry?.q === 'string' && entry.q.trim()) return entry.q.trim();\n  if (Array.isArray(entry?.keywords) && entry.keywords.length > 0) {\n    const joined = entry.keywords.filter((k) => typeof k === 'string' && k.trim()).join(' ').trim();\n    if (joined) return joined;\n  }","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/providers/a16z-speedrun-talent.mjs#L31-L67","documentation":"assertFeedUrl in providers/a16z-speedrun-talent.mjs throws this when the URL is valid HTTPS but its hostname does not exactly equal the provider's TRUSTED_HOST. This is an SSRF/misconfiguration guard: the provider fetches only from its one known feed host, and any other hostname is rejected even if it is a plausible mirror or subdomain.","triggerScenarios":"A feed URL pointing at a different domain, a subdomain variant, a staging mirror, or a typo'd host — parsed fine, https fine, but parsed.hostname !== TRUSTED_HOST.","commonSituations":"Config copied from another provider with a different TRUSTED_HOST; a custom portals.yml entry pointing at the company site instead of the feed host; DNS/CNAME assumptions that do not change the literal hostname string.","solutions":["Correct the URL's hostname to exactly match TRUSTED_HOST as defined at the top of providers/a16z-speedrun-talent.mjs.","If you meant a different feed, note that host is intentionally unsupported — remove the entry or use the official feed.","Print new URL(url).hostname to compare character-by-character with TRUSTED_HOST (watch for 'www.' prefixes and typos)."],"exampleFix":"// before\nfetchSpeedrunFeed('https://speedrun.example.com/feed')\n// after\nfetchSpeedrunFeed('https://a16z-speedrun.com/feed') // exact TRUSTED_HOST","handlingStrategy":"validation","validationCode":"const u = new URL(rawUrl);\nif (u.hostname !== TRUSTED_HOST) throw new Error(`feed host must be ${TRUSTED_HOST}, got ${u.hostname}`);","typeGuard":"function isTrustedSpeedrunUrl(url) {\n  try { const u = new URL(url); return u.protocol === 'https:' && u.hostname === TRUSTED_HOST; }\n  catch { return false; }\n}","tryCatchPattern":"try {\n  await fetchSpeedrunFeed(url);\n} catch (e) {\n  if (String(e.message).includes('untrusted hostname')) {\n    console.error(`Config error: expected host ${TRUSTED_HOST}, got: ${url}`);\n    return null;\n  } else throw e;\n}","preventionTips":["Keep the trusted host as the single source of truth; build feed URLs from it.","Compare hostnames exactly — beware 'www.' prefixes and lookalike domains.","When migrating configs between providers, update the host check, not just the URL.","Test config URLs against TRUSTED_HOST in CI."],"tags":["url-validation","ssrf-protection","hostname","provider"],"backgroundTag":"invalid-url","analyzedSha":"aac998c7ed7248ea853b720ceeb1fdbeb322fc5d","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}