{"record":{"id":"a2f04d3f19776134","repo":"santifer/career-ops","slug":"comeet-invalid-url-redacttoken-url","errorCode":null,"errorMessage":"comeet: invalid URL: ${redactToken(url)}","messagePattern":"comeet: invalid URL: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"providers/comeet.mjs","lineNumber":34,"sourceCode":"/** @param {unknown} raw */\nfunction isComeetApiUrl(raw) {\n  if (typeof raw !== 'string' || !raw) return false;\n  let parsed;\n  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 {","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/comeet.mjs#L16-L52","documentation":"Thrown by comeet's assertComeetUrl when the URL cannot be parsed by new URL() at all. Note this is a defense-in-depth re-check: through the public fetch() path it is effectively unreachable, because resolveApiUrl first runs isComeetApiUrl (which itself does new URL() in a try/catch and returns null on failure, surfacing as error 165 instead). assertComeetUrl is the second line of defence, reachable when it is invoked directly (e.g. a custom integration or unit test) with a malformed string.","triggerScenarios":"assertComeetUrl is called directly with a value that is not a valid URL — empty string, a relative path, a string with illegal characters, or a non-URL scalar. The token is redacted in the message via redactToken so the thrown string never leaks the secret.","commonSituations":"Unit tests or a bespoke integration that calls assertComeetUrl on raw input; a future refactor that makes resolveApiUrl and assertComeetUrl source the URL differently. Normal scan/fetch use does not reach this branch.","solutions":["If calling assertComeetUrl directly, parse the value with new URL() yourself first and skip/handle non-URLs.","For normal fetch() use, fix the entry config so resolveApiUrl returns a value (see error 165) — this branch will not fire otherwise.","Confirm the two functions have not diverged: both should treat a non-URL string as a resolution failure (165), not an assertion failure (161)."],"exampleFix":"// before — direct call on raw input\nassertComeetUrl(maybeUrl); // throws if maybeUrl is 'not a url'\n\n// after — validate first\ntry { new URL(maybeUrl); } catch { /* not a URL, skip */ }","handlingStrategy":"validation","validationCode":"// Through fetch() this is pre-empted by error 165. For a direct assertComeetUrl call:\nfunction isParseableUrl(u) {\n  try { new URL(u); return true; } catch { return false; }\n}\nif (!isParseableUrl(maybeUrl)) { /* skip, do not call assertComeetUrl */ }","typeGuard":"function isParseableUrl(u) {\n  if (typeof u !== 'string' || !u) return false;\n  try { new URL(u); return true; } catch { return false; }\n}","tryCatchPattern":"// Only relevant for direct assertComeetUrl callers.\ntry { assertComeetUrl(url); }\ncatch (e) {\n  if (/^comeet: invalid URL/.test(e.message)) { /* input wasn't a URL — skip */ }\n  else throw e;\n}","preventionTips":["For normal use, configure entry.api correctly (see error 165) — 161 is unreachable via fetch().","If calling assertComeetUrl directly, pre-parse with new URL().","Never pass user-supplied raw strings straight into the assert."],"tags":["url-validation","comeet","ssrf","defense-in-depth","token-redaction"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}