{"record":{"id":"280485972fd101e4","repo":"santifer/career-ops","slug":"pinpoint-untrusted-hostname-parsed-hostname","errorCode":null,"errorMessage":"pinpoint: untrusted hostname \"${parsed.hostname}\" — must match <slug>.pinpointhq.com","messagePattern":"pinpoint: untrusted hostname \"(.+?)\" — must match <slug>\\.pinpointhq\\.com","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/pinpoint.mjs","lineNumber":34,"sourceCode":"\n// The tenant label must be a valid DNS label: it may contain hyphens but must\n// not start or end with one (so `acme-.pinpointhq.com` is rejected). The\n// optional trailing group keeps single-character labels (e.g. `a.pinpointhq.com`)\n// valid. detect() and fetch() both route through this constant via\n// resolveApiUrl()/assertPinpointUrl(), so the stricter check applies everywhere.\nconst PINPOINT_HOST_RE = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.pinpointhq\\.com$/;\n\n/** @param {string} url */\nfunction assertPinpointUrl(url) {\n  let parsed;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`pinpoint: invalid URL: ${url}`);\n  }\n  if (parsed.protocol !== 'https:') throw new Error(`pinpoint: URL must use HTTPS: ${url}`);\n  if (!PINPOINT_HOST_RE.test(parsed.hostname)) {\n    throw new Error(`pinpoint: untrusted hostname \"${parsed.hostname}\" — must match <slug>.pinpointhq.com`);\n  }\n  return url;\n}\n\nfunction resolveApiUrl(entry) {\n  const raw = typeof entry.careers_url === 'string' ? entry.careers_url : '';\n  if (!raw) return null;\n  let parsed;\n  try {\n    parsed = new URL(raw);\n  } catch {\n    return null;\n  }\n  if (parsed.protocol !== 'https:') return null;\n  if (!PINPOINT_HOST_RE.test(parsed.hostname)) return null;\n  return `https://${parsed.hostname}/postings.json`;\n}\n","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/pinpoint.mjs#L16-L52","documentation":"The pinpoint provider rejects an API URL whose hostname does not match the strict allowlist regex PINPOINT_HOST_RE (/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.pinpointhq\\.com$/). This is an SSRF guard: it pins every request to a genuine <slug>.pinpointhq.com tenant subdomain so a crafted entry cannot redirect the fetch to an attacker-controlled or internal host. The slug must start and end alphanumeric with optional interior hyphens.","triggerScenarios":"assertPinpointUrl throws when parsed.hostname fails the regex — e.g. a careers_url pointing to a custom branded domain (jobs.acme.com), a hostname with uppercase letters (Acme.pinpointhq.com), a leading/trailing hyphen in the slug (-acme.pinpointhq.com), or a hostname like pinpointhq.com with no slug prefix at all.","commonSituations":"A job_boards entry was auto-detected from a non-Pinpoint URL but routed to the pinpoint provider; a user pasted a Pinpoint vanity/branded domain that does not carry the pinpointhq.com suffix; the entry's careers_url was typo'd with a trailing dot or wrong TLD.","solutions":["Confirm the entry's careers_url is literally https://<slug>.pinpointhq.com where <slug> is lowercase, starts and ends with a letter or digit, and uses only hyphens in between.","If the tenant uses a branded custom domain, the pinpoint provider cannot auto-derive it — set provider explicitly to the correct provider or supply api: with the canonical pinpointhq.com subdomain.","Strip any trailing slash, port, or uppercase characters from the hostname before validation.","Verify the entry object passed to fetch() has not been mutated downstream to carry a resolved URL from a different host."],"exampleFix":"// before\nconst entry = { name: 'Acme', careers_url: 'https://jobs.acme.com' };\n// after — canonical Pinpoint subdomain\nconst entry = { name: 'Acme', careers_url: 'https://acme.pinpointhq.com' };","handlingStrategy":"validation","validationCode":"const PINPOINT_HOST_RE = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.pinpointhq\\.com$/;\nfunction isValidPinpointUrl(url) {\n  try {\n    const p = new URL(url);\n    return p.protocol === 'https:' && PINPOINT_HOST_RE.test(p.hostname);\n  } catch { return false; }\n}\n// call before provider.fetch\nif (!isValidPinpointUrl(entry.careers_url)) {\n  console.warn(`skip ${entry.name}: not a valid pinpointhq.com URL`);\n}","typeGuard":"null","tryCatchPattern":"try {\n  await provider.fetch(entry, ctx);\n} catch (e) {\n  if (/pinpoint: untrusted hostname/.test(e.message)) {\n    // config issue, not transient — log and skip this entry\n    console.warn(`[skip] ${entry.name}: ${e.message}`);\n  } else throw e;\n}","preventionTips":["Always run provider.detect(entry) before fetch(); it returns null instead of throwing when the URL does not resolve.","Normalize careers_url to lowercase and strip trailing slashes before storing.","Maintain a config validator that checks every pinpoint entry against the hostname regex at load time."],"tags":["ssrf","url-validation","hostname-allowlist","provider","pinpoint","security"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}