santifer/career-ops · error · Error

larajobs: untrusted hostname "${parsed.hostname}" - must be

Error message

larajobs: untrusted hostname "${parsed.hostname}" - must be ${TRUSTED_HOST}

What it means

The third guard in assertLarajobsUrl: even a valid HTTPS URL must have hostname exactly equal to TRUSTED_HOST ('larajobs.com'). Any other host — including look-alikes or subdomains — is rejected. This is an SSRF defence: it stops a config change from making the scanner fetch an attacker-controlled or off-brand endpoint.

Source

Thrown at providers/larajobs.mjs:28

// `<job:company>` and `<job:location>`, so company and location come straight
// from the feed (no title-splitting heuristics needed).
//
// Wire in via a `job_boards:` entry with `provider: larajobs`.

const FEED_URL = 'https://larajobs.com/feed';
const TRUSTED_HOST = 'larajobs.com';

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

// NaN-safe Date.parse - `|| undefined` would also coerce a valid epoch 0.
function toEpochMs(value) {
  if (!value) return undefined;
  const parsed = Date.parse(value);
  return Number.isNaN(parsed) ? undefined : parsed;
}

function fallbackCompany(entry) {
  return typeof entry?.name === 'string' && entry.name.trim() ? entry.name.trim() : 'LaraJobs';
}

/** @type {Provider} */
export default {
  id: 'larajobs',

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Correct the URL to use exactly https://larajobs.com (no subdomain).
  2. If the feed legitimately moved hosts, update TRUSTED_HOST in providers/larajobs.mjs after verifying the new host is the official Larajobs endpoint.
  3. Audit git history of portals.yml for the offending change.

Example fix

// before
api: https://www.larajobs.com/feed

// after
api: https://larajobs.com/feed
Defensive patterns

Strategy: validation

Validate before calling

import { URL } from 'node:url';
const TRUSTED = new Set(['larajobs.com']);
export function isTrustedLarajobsHost(value) {
  try { return TRUSTED.has(new URL(value).hostname); } catch { return false; }
}

Type guard

/** @param {string} url */
function isLarajobsHost(url) {
  try { return new URL(url).hostname === 'larajobs.com'; } catch { return false; }
}

Try / catch

try {
  assertLarajobsUrl(url);
} catch (err) {
  // an untrusted-host error is a security signal — log loudly, do not silently fall back
  if (err.message.includes('untrusted hostname')) console.error(`[security] ${err.message}`);
  throw err;
}

Prevention

When it happens

Trigger: An HTTPS URL whose hostname is not 'larajobs.com' — e.g. www.larajobs.com, api.larajobs.com, larajobs.com.evil.com, feed.larajobs.net, or an internal IP/host. The offending hostname is interpolated into the message.

Common situations: Someone added a www. prefix or a subdomain; a copy-paste brought in a similar domain; a malicious or mistaken config points the feed elsewhere; the trusted host genuinely moved and the constant needs updating.

Related errors


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