santifer/career-ops · error · Error

landingjobs: untrusted hostname "${parsed.hostname}" — must

Error message

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

What it means

Thrown by assertLandingUrl() when the parsed URL's hostname is not exactly 'landing.jobs' (TRUSTED_HOST). The provider hard-pins the single trusted host and refuses any other hostname to prevent SSRF via redirect or a tampered entry pointing at an internal or attacker-controlled server. Note www.landing.jobs or any subdomain is also rejected since the check is an exact match.

Source

Thrown at providers/landingjobs.mjs:30

// `company` is derived best-effort from that slug (humanized) and falls back to
// the portal entry name. The whole active set is returned in one call.
//
// Wire in via a `job_boards:` entry with `provider: landingjobs`.

const FEED_URL = 'https://landing.jobs/api/v1/jobs';
const TRUSTED_HOST = 'landing.jobs';

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

// NaN-safe Date.parse.
function toEpochMs(value) {
  if (typeof value !== 'string' || !value) return undefined;
  const parsed = Date.parse(value);
  return Number.isNaN(parsed) ? undefined : parsed;
}

/**
 * Derive a best-effort company name from a Landing.jobs posting URL.
 * Posting URLs are `https://landing.jobs/at/<slug>/<job>`; the `<slug>` is
 * humanized (hyphens/underscores → spaces, title-cased). Returns '' when the
 * URL is not the expected `/at/<slug>/…` shape. Exported for unit tests.
 * @param {string} url
 */

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Use the canonical host landing.jobs (drop any www or subdomain prefix).
  2. If the company is not on landing.jobs, switch the entry's provider to the correct ATS.
  3. Confirm the URL is https://landing.jobs/... with no subdomain.

Example fix

# before
acme:
  provider: landingjobs
  api: https://www.landing.jobs/api/v1/jobs

# after
acme:
  provider: landingjobs
  api: https://landing.jobs/api/v1/jobs
Defensive patterns

Strategy: validation

Validate before calling

function isTrustedLandingHost(url) {
  try { return new URL(url).hostname === 'landing.jobs'; } catch { return false; }
}

Type guard

/** @param {string} url @returns {boolean} */
function isLandingJobsHttpsUrl(url) {
  try {
    const p = new URL(url);
    return p.protocol === 'https:' && p.hostname === 'landing.jobs';
  } catch { return false; }
}

Prevention

When it happens

Trigger: An api/careers_url pointing at a different domain (www.landing.jobs, a proxy, an internal IP, a lookalike); a CNAME or vanity domain not equal to landing.jobs; using the landingjobs provider for a non-landing.jobs board.

Common situations: A www-prefixed URL the user assumed was equivalent; pointing the provider at a proxy/mirror; selecting the wrong provider for a board that isn't landing.jobs.

Related errors


AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13). Data as JSON: /api/errors/12d6ac28a7e6cfbe. Report an issue: GitHub.