{"record":{"id":"2881fbc8e24e2687","repo":"santifer/career-ops","slug":"comeet-untrusted-hostname-parsed-hostname","errorCode":null,"errorMessage":"comeet: untrusted hostname \"${parsed.hostname}\" — must be ${COMEET_API_HOST}","messagePattern":"comeet: untrusted hostname \"(.+?)\" — must be (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"providers/comeet.mjs","lineNumber":38,"sourceCode":"  try {\n    parsed = new URL(raw);\n  } catch {\n    return false;\n  }\n  return parsed.protocol === 'https:' && parsed.hostname === COMEET_API_HOST && parsed.pathname.startsWith('/careers-api/');\n}\n\n/** @param {string} url */\nfunction assertComeetUrl(url) {\n  let parsed;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`comeet: invalid URL: ${redactToken(url)}`);\n  }\n  if (parsed.protocol !== 'https:') throw new Error(`comeet: URL must use HTTPS: ${redactToken(url)}`);\n  if (parsed.hostname !== COMEET_API_HOST)\n    throw new Error(`comeet: untrusted hostname \"${parsed.hostname}\" — must be ${COMEET_API_HOST}`);\n  if (!parsed.pathname.startsWith('/careers-api/'))\n    throw new Error(`comeet: URL path must be the careers-api endpoint: ${redactToken(url)}`);\n  return url;\n}\n\n// Redact the per-tenant ?token= so neither the (informational, possibly-logged)\n// DetectHit url nor a thrown validation error carries the secret. Best-effort:\n// falls back to a regex strip when the value can't be parsed as a URL.\nfunction redactToken(url) {\n  try {\n    const parsed = new URL(url);\n    if (parsed.searchParams.has('token')) parsed.searchParams.set('token', 'REDACTED');\n    return parsed.href;\n  } catch {\n    return typeof url === 'string' ? url.replace(/([?&]token=)[^&#]*/gi, '$1REDACTED') : url;\n  }\n}\n","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/comeet.mjs#L20-L56","documentation":"Thrown by comeet's assertComeetUrl when the URL is valid https but its hostname is not exactly www.comeet.co (COMEET_API_HOST). Comeet's careers API lives on a single fixed origin, so the SSRF defence pins the hostname rather than allowing per-tenant subdomains. This is defense-in-depth: resolveApiUrl's isComeetApiUrl enforces the identical hostname check and returns null (→ error 165) first, so fetch() surfaces 165 rather than 163. Reachable via a direct assertComeetUrl call.","triggerScenarios":"assertComeetUrl is called directly with an https URL on a different host (e.g. www.comeet.com, a tenant CNAME, or an attacker-controlled host). Through fetch(), a non-www.comeet.co entry fails isComeetApiUrl and reports as error 165.","commonSituations":"Confusing the branded www.comeet.com page with the API host www.comeet.co; a direct integration test pointing at a mock host; an attempted SSRF via a crafted api: value (which fetch() rejects as 165).","solutions":["For direct calls, pass only https://www.comeet.co/careers-api/... URLs.","For fetch() use, ensure entry.api is on www.comeet.co (this shows as 165, same fix).","Do not attempt to point the comeet provider at a proxy or alternate host — the host is intentionally non-configurable."],"exampleFix":"// before — wrong host (the branded page, not the API)\nassertComeetUrl('https://www.comeet.com/careers-api/2.0/company/abc/positions?token=x');\n\n// after — exact API host\nassertComeetUrl('https://www.comeet.co/careers-api/2.0/company/abc/positions?token=x');","handlingStrategy":"validation","validationCode":"const COMEET_API_HOST = 'www.comeet.co';\nfunction isComeetHost(u) {\n  try { return new URL(u).hostname === COMEET_API_HOST; } catch { return false; }\n}","typeGuard":"function isOnComeetApiHost(u) {\n  if (typeof u !== 'string' || !u) return false;\n  try { return new URL(u).hostname === 'www.comeet.co'; } catch { return false; }\n}","tryCatchPattern":"try { assertComeetUrl(url); }\ncatch (e) {\n  if (/^comeet: untrusted hostname/.test(e.message)) { /* wrong host — do not follow redirects, skip */ }\n  else throw e;\n}","preventionTips":["The Comeet API host is a fixed origin (www.comeet.co) — never configurable.","Do not alias it to a proxy or alternate domain.","Through fetch() this is pre-empted by 165."],"tags":["url-validation","comeet","ssrf","hostname-pin","defense-in-depth"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}