santifer/career-ops · error

getonbrd: untrusted hostname

Error message

getonbrd: untrusted hostname "${parsed.hostname}" — must be ${TRUSTED_HOST}

What it means

assertGetonbrdUrl restricts URLs to a single trusted host, TRUSTED_HOST = 'www.getonbrd.com'. If the parsed URL is valid HTTPS but points at any other hostname (apex domain getonbrd.com without www, a mirror, or an unrelated host), the function throws this error naming the offending hostname. This is an SSRF/spoofing guard: category slugs and entry URLs are config-derived, so the host allowlist prevents a bad config from pointing the fetcher anywhere else.

Solutions

  1. Use exactly https://www.getonbrd.com (with the www prefix) as the host in the entry
  2. Check for typos or lookalike domains in the configured URL
  3. If you need a different host, the provider does not support it — the allowlist is a hard security boundary, so remove the custom URL and rely on the default feed host

Example fix

// before
careers_url: https://getonbrd.com/api/v0/categories/programming/jobs
// after
careers_url: https://www.getonbrd.com/api/v0/categories/programming/jobs
Defensive patterns

Strategy: validation

Validate before calling

const TRUSTED = 'www.getonbrd.com';
const u = new URL(entry.careers_url);
if (u.protocol !== 'https:' || u.hostname !== TRUSTED) throw new Error(`getonbrd entry ${entry.name}: URL must be https://${TRUSTED}/...`);

Type guard

function isTrustedGetonbrdUrl(v) { try { const u = new URL(v); return u.protocol === 'https:' && u.hostname === 'www.getonbrd.com'; } catch { return false; } }

Try / catch

try {
  assertGetonbrdUrl(url);
} catch (e) {
  if (String(e.message).includes('untrusted hostname')) {
    console.error(`Point getonbrd entries at https://www.getonbrd.com only; got: ${url}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: A portals.yml entry uses https://getonbrd.com/... (missing the www. prefix), a typo'd or lookalike domain (getonbrd.co, getonboard.com), or any third-party URL fed to the getonbrd provider.

Common situations: Omitting 'www.' by hand; assuming the apex domain is equivalent to the canonical host; trying to point the provider at a staging or proxy host; paste errors from a search result.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16). Data as JSON: /api/errors/a9cb2ce6401ae6de. Report an issue: GitHub.

Appendix: source

Thrown at providers/getonbrd.mjs:85

  if (out.length > MAX_CATEGORIES) {
    throw new Error(
      `getonbrd: ${out.length} categories configured — cap is ${MAX_CATEGORIES} (each one costs up to max_pages requests)`,
    );
  }
  return out;
}

/** @param {string} url */
function assertGetonbrdUrl(url) {
  let parsed;
  try {
    parsed = new URL(url);
  } catch {
    throw new Error(`getonbrd: invalid URL: ${url}`);
  }
  if (parsed.protocol !== 'https:') throw new Error(`getonbrd: URL must use HTTPS: ${url}`);
  if (parsed.hostname !== TRUSTED_HOST) {
    throw new Error(`getonbrd: untrusted hostname "${parsed.hostname}" — must be ${TRUSTED_HOST}`);
  }
  return url;
}

/** Resolve the page cap: a positive integer `max_pages` on the entry, capped. */
function resolveMaxPages(entry) {
  const v = entry?.max_pages;
  if (Number.isInteger(v) && v > 0) return Math.min(v, MAX_PAGES_CAP);
  return DEFAULT_MAX_PAGES;
}

/**
 * Normalize a single Get on Board job (JSON:API resource). Exported for tests.
 *
 * Field mapping → the normalized Job shape:
 *   - title:    `attributes.title`, trimmed (items without one are dropped).
 *   - url:      `links.public_url` — an absolute `https:` posting URL host-locked
 *               to www.getonbrd.com (off-host or non-https drops the item). It is

View on GitHub (pinned to aac998c7ed)