santifer/career-ops · error · Error
manfred: untrusted hostname "${parsed.hostname}" — must be $
Error message
manfred: untrusted hostname "${parsed.hostname}" — must be ${TRUSTED_HOST} What it means
Third guard in assertManfredUrl: parsed.hostname must equal TRUSTED_HOST ('www.getmanfred.com'). Any other host is rejected. This is the SSRF allowlist — it prevents a config or construction error from directing the fetch at an off-brand or attacker-controlled host. The offending hostname is interpolated into the message.
Source
Thrown at providers/manfred.mjs:37
// Wire in via a `job_boards:` entry with `provider: manfred`.
const FEED_BASE = 'https://www.getmanfred.com/api/v2/public/offers';
const TRUSTED_HOST = 'www.getmanfred.com';
const OFFER_BASE = 'https://www.getmanfred.com/ofertas-empleo';
const VALID_LANGS = ['EN', 'ES'];
const DEFAULT_LANG = 'EN';
/** @param {string} url */
function assertManfredUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`manfred: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`manfred: URL must use HTTPS: ${url}`);
if (parsed.hostname !== TRUSTED_HOST) {
throw new Error(`manfred: untrusted hostname "${parsed.hostname}" — must be ${TRUSTED_HOST}`);
}
return url;
}
/** Resolve the feed language: `lang` on the entry, uppercased, else EN. */
export function resolveLang(entry) {
const raw = typeof entry?.lang === 'string' ? entry.lang.trim().toUpperCase() : '';
return VALID_LANGS.includes(raw) ? raw : DEFAULT_LANG;
}
// The feed reports currency as the SYMBOL, not an ISO code, and the observed
// values include a narrow-no-break-space variant of the euro sign. scan.mjs's
// salary_filter compares currencies case-insensitively as plain strings, so a
// symbol would never match a user's `currency: EUR` — map to ISO, and drop the
// field entirely rather than guess when the symbol is unknown.
const CURRENCY_BY_SYMBOL = new Map([
['€', 'EUR'],
['£', 'GBP'],View on GitHub (pinned to 9b17a8ac97)
Solutions
- Use exactly https://www.getmanfred.com/... (include the www).
- If the host legitimately moved, verify the new official host and update TRUSTED_HOST in providers/manfred.mjs.
- Audit how the URL was constructed (apex vs www is the most common slip).
Example fix
// before feedUrl = 'https://getmanfred.com/api/v2/public/offers' // after feedUrl = 'https://www.getmanfred.com/api/v2/public/offers'
Defensive patterns
Strategy: validation
Validate before calling
import { URL } from 'node:url';
const TRUSTED = new Set(['www.getmanfred.com']);
export function isTrustedManfredHost(value) {
try { return TRUSTED.has(new URL(value).hostname); } catch { return false; }
} Type guard
/** @param {string} url */
function isManfredHost(url) {
try { return new URL(url).hostname === 'www.getmanfred.com'; } catch { return false; }
} Try / catch
try {
assertManfredUrl(url);
} catch (err) {
if (err.message.includes('untrusted hostname')) console.error(`[security] ${err.message}`);
throw err;
} Prevention
- Always include the www subdomain for getmanfred.com URLs.
- Treat an untrusted-hostname error as a potential SSRF signal, not a typo to silence.
- Extend TRUSTED_HOST only after verifying the new host is an official Manfred endpoint.
- Lint config to catch apex-domain (getmanfred.com) slips.
When it happens
Trigger: An HTTPS URL whose hostname is not 'www.getmanfred.com' — e.g. getmanfred.com (apex, missing www.), api.getmanfred.com, www.getmanfred.com.evil.com, or an unrelated host.
Common situations: The apex domain (getmanfred.com) was used instead of www; a subdomain typo; a copied URL pointed at a different domain; the trusted host genuinely changed and the constant needs updating.
Related errors
- larajobs: untrusted hostname "${parsed.hostname}" - must be
- lever: untrusted hostname "${parsed.hostname}" — must be one
- Refusing non-HTTP(S) URL: ${url}
- arbeitnow: untrusted hostname "${parsed.hostname}" — must be
- ashby: untrusted hostname "${parsed.hostname}" — must be one
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/4bc2e5b6af01af44.
Report an issue: GitHub.