santifer/career-ops · error · Error

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

Error message

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

What it means

After passing scheme checks, assertTorreUrl enforces a single trusted API host (TRUSTED_API_HOST). This error is thrown when the hostname differs — including lookalike/subdomain variants. Like its Muse counterpart, this is the SSRF/pin allowlist that stops fetches to attacker-controlled or redirected hosts.

Source

Thrown at providers/torre.mjs:94

  'potential-to-develop',
  '1-plus-year',
  '2-plus-years',
  '3-plus-years',
  '5-plus-years',
]);
const DEFAULT_EXPERIENCE = '1-plus-year';

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

/**
 * Build the search body from the portal entry. Only filters proven to affect
 * `total` are emitted — see the header note. Exported for tests.
 *
 * @param {any} entry
 * @returns {object}
 */
export function buildTorreQuery(entry) {
  /** @type {Record<string, unknown>} */
  const body = {};

  const search = typeof entry?.search === 'string' ? entry.search.trim() : '';
  if (search) {
    // `experience` is mandatory here — omitting it is a hard 500, so it is

View on GitHub (pinned to 1696bec4d0)

Solutions

  1. Correct the hostname to exactly the pinned TRUSTED_API_HOST (check the constant at the top of providers/torre.mjs).
  2. Strip redirect/tracking wrappers to recover the genuine Torre API URL before validating.
  3. If Torre changed its API host officially, verify and update TRUSTED_API_HOST in providers/torre.mjs — do not loosen the check to a suffix match.
  4. Route URLs for other hosts to their proper providers instead of forcing them through the Torre provider.

Example fix

// before (provider pinned to api.torre.ai)
assertTorreUrl('https://torre.co/api/v2');
// Error: untrusted hostname "torre.co" — must be api.torre.ai
// after
assertTorreUrl('https://api.torre.ai/api/v2');
Defensive patterns

Strategy: validation

Validate before calling

const TRUSTED_API_HOST = 'api.torre.ai'; // match the constant in providers/torre.mjs
function isTrustedTorreUrl(url) {
  try {
    const u = new URL(url);
    return u.protocol === 'https:' && u.hostname === TRUSTED_API_HOST;
  } catch { return false; }
}

Type guard

function isTorreApiUrl(v) {
  if (typeof v !== 'string') return false;
  try {
    const u = new URL(v);
    return u.protocol === 'https:' && u.hostname === 'api.torre.ai';
  } catch { return false; }
}

Try / catch

try {
  assertTorreUrl(url);
} catch (err) {
  if (String(err.message).includes('untrusted hostname')) {
    console.error(`Rejecting non-Torre host (possible SSRF/mirror): ${err.message}`);
    return null; // skip this URL
  } else throw err;
}

Prevention

When it happens

Trigger: Calling assertTorreUrl with a URL on a different host or subdomain than the pinned Torre API host — e.g. 'www.torre.ai' when only 'torre.ai' is trusted, 'api.torre.co' (old domain), or 'torre.ai.evil.io'.

Common situations: Torre domain migration (torre.co → torre.ai style) leaving old URLs in config; adding/omitting 'www.'; third-party mirrors or job aggregators linking to copies of Torre postings; malicious URLs from untrusted input.

Related errors


AI-assisted analysis of santifer/career-ops@1696bec4d0 (2026-09-01). Data as JSON: /api/errors/daf81efe20054a79. Report an issue: GitHub.