santifer/career-ops · error · Error

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

Error message

justjoin: untrusted hostname "${parsed.hostname}" — must be justjoin.it

What it means

Thrown by assertJustJoinUrl() when the parsed URL's hostname is not exactly 'justjoin.it' (the sole entry in ALLOWED_HOSTS). The provider refuses to fetch any other host to prevent SSRF via redirect or a tampered entry pointing at an internal/attacker server. Note www.justjoin.it or any subdomain is also rejected since the set is a strict exact match.

Source

Thrown at providers/justjoin.mjs:23

// Browser URLs under https://justjoin.it/job-offers/... are accepted for
// detection, but fetches use https://justjoin.it/api/candidate-api/offers.

const ALLOWED_HOSTS = new Set(['justjoin.it']);
const API_BASE = 'https://justjoin.it/api/candidate-api/offers';
const JOB_BASE = 'https://justjoin.it/job-offer/';
const PAGE_SIZE = 100;
const MAX_PAGES = 50;

function assertJustJoinUrl(url) {
  let parsed;
  try {
    parsed = new URL(url);
  } catch {
    throw new Error(`justjoin: invalid URL: ${url}`);
  }
  if (parsed.protocol !== 'https:') throw new Error(`justjoin: URL must use HTTPS: ${url}`);
  if (!ALLOWED_HOSTS.has(parsed.hostname)) {
    throw new Error(`justjoin: untrusted hostname "${parsed.hostname}" — must be justjoin.it`);
  }
  if (!parsed.pathname.startsWith('/job-offers') && parsed.pathname !== '/api/candidate-api/offers') {
    throw new Error(`justjoin: URL path must be /job-offers or /api/candidate-api/offers: ${url}`);
  }
  return parsed;
}

function detectUrl(entry) {
  const url = entry.api || entry.careers_url || '';
  if (typeof url !== 'string' || !url.trim()) return null;
  try {
    const parsed = assertJustJoinUrl(url);
    return { url: parsed.href };
  } catch {
    return null;
  }
}

View on GitHub (pinned to 9b17a8ac97)

Solutions

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

Example fix

# before
acme:
  provider: justjoin
  api: https://www.justjoin.it/api/candidate-api/offers

# after
acme:
  provider: justjoin
  api: https://justjoin.it/api/candidate-api/offers
Defensive patterns

Strategy: validation

Validate before calling

function isTrustedJustJoinHost(url) {
  try { return new URL(url).hostname === 'justjoin.it'; } catch { return false; }
}

Type guard

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

Prevention

When it happens

Trigger: An api/careers_url pointing at a different domain (www.justjoin.it, an API proxy, an internal IP); a CNAME or vanity domain that isn't in the allow-list; an attempt to use the justjoin provider for a non-justjoin board.

Common situations: A www-prefixed URL that the user assumed was equivalent; pointing the provider at a proxy or mirror; wrong provider selected for a board.

Related errors


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