{"record":{"id":"501a10bd3be7336a","repo":"santifer/career-ops","slug":"agentic-jobs-untrusted-hostname-parsed-hostnam","errorCode":null,"errorMessage":"agentic-jobs: untrusted hostname \"${parsed.hostname}\" — must be ${TRUSTED_HOST}","messagePattern":"agentic-jobs: untrusted hostname \"(.+?)\" — must be (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/agentic-jobs.mjs","lineNumber":49,"sourceCode":"const SITE_ORIGIN = 'https://agentic-engineering-jobs.com';\nconst API_BASE = `${SITE_ORIGIN}/api/v1`;\nconst TRUSTED_HOST = 'agentic-engineering-jobs.com';\nconst PAGE_SIZE = 50; // fixed by the API (meta.per_page)\nconst MAX_PAGES = 40; // safety cap on request count (40*50 = 2000 postings)\nconst MAX_JOBS = 2000;\nconst PAGE_DELAY_MS = 2100; // stays under the documented 30 req/60s limit\n\n/** @param {string} url */\nfunction assertAgenticUrl(url) {\n  let parsed;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`agentic-jobs: invalid URL: ${url}`);\n  }\n  if (parsed.protocol !== 'https:') throw new Error(`agentic-jobs: URL must use HTTPS: ${url}`);\n  if (parsed.hostname !== TRUSTED_HOST) {\n    throw new Error(`agentic-jobs: untrusted hostname \"${parsed.hostname}\" — must be ${TRUSTED_HOST}`);\n  }\n  return url;\n}\n\nconst regionNames = new Intl.DisplayNames(['en'], { type: 'region' });\n\n/**\n * Resolve a two-letter ISO country code to an English name. Returns '' for\n * anything that isn't a resolvable two-letter code. Exported for tests.\n * @param {unknown} code\n */\nexport function countryName(code) {\n  if (typeof code !== 'string' || !/^[A-Za-z]{2}$/.test(code)) return '';\n  try {\n    const name = regionNames.of(code.toUpperCase());\n    return name && name !== code.toUpperCase() ? name : '';\n  } catch {\n    return '';","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/agentic-jobs.mjs#L31-L67","documentation":"The final agentic-jobs URL guard pins the hostname to TRUSTED_HOST ('agentic-engineering-jobs.com'). Any other hostname is rejected as an SSRF allowlist violation — the provider only ever fetches from its one known API host. Combined with redirect:'error' on the fetch, this closes both the redirect and direct-misconfiguration SSRF vectors.","triggerScenarios":"The parsed URL hostname differs from TRUSTED_HOST: a wrong subdomain, a different domain, or an internal host/IP. Server-side redirects are already blocked by redirect:'error', so this catches a directly-misconfigured API_BASE.","commonSituations":"API_BASE edited to a wrong host (e.g. a mirror or the marketing site); TRUSTED_HOST not updated after upstream renamed; 'www.' subdomain prefix mismatch.","solutions":["Confirm TRUSTED_HOST at the top of providers/agentic-jobs.mjs is the real API host and API_BASE uses that exact host.","Avoid subdomain variants unless TRUSTED_HOST is updated to allow them (kept tight by design)."],"exampleFix":"// before\nconst TRUSTED_HOST = 'www.agentic-engineering-jobs.com'; // wrong subdomain\nconst API_BASE = `https://${TRUSTED_HOST}/api`;\n\n// after\nconst TRUSTED_HOST = 'agentic-engineering-jobs.com';\nconst API_BASE = `https://${TRUSTED_HOST}/api`;","handlingStrategy":"validation","validationCode":"const TRUSTED_HOST = 'agentic-engineering-jobs.com';\nfunction isTrustedApiUrl(u) {\n  try {\n    const p = new URL(u);\n    return p.protocol === 'https:' && p.hostname === TRUSTED_HOST;\n  } catch { return false; }\n}\nif (!isTrustedApiUrl(API_BASE)) throw new Error('agentic-jobs API host not trusted');","typeGuard":"/** @param {unknown} u @param {string} host @returns {u is string} */\nfunction isTrustedHostUrl(u, host) {\n  if (typeof u !== 'string') return false;\n  try { return new URL(u).hostname === host; } catch { return false; }\n}","tryCatchPattern":"try { assertAgenticUrl(url); } catch (err) {\n  if (/untrusted hostname/.test(err.message)) console.error('agentic-jobs API host must be', TRUSTED_HOST);\n  throw err;\n}","preventionTips":["Keep TRUSTED_HOST tight; pair with redirect:'error' (this provider does) to close redirect-SSRF.","Lint against widening the allowlist without an explicit code review."],"tags":["agentic-jobs","ssrf-guard","allowlist","provider","security","url"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}