santifer/career-ops · error · Error
jobspresso: untrusted hostname "${parsed.hostname}" - must b
Error message
jobspresso: untrusted hostname "${parsed.hostname}" - must be ${TRUSTED_HOST} What it means
Thrown by assertJobspressoUrl when the URL's hostname is not exactly jobspresso.co (strict equality, no subdomain tolerance). This is the core SSRF allowlist guard. The shipped provider only passes the hardcoded jobspresso.co constant, so it cannot fire unless the constant or the function's input changes.
Source
Thrown at providers/jobspresso.mjs:25
// approach as providers/personio.mjs rather than adding an XML dependency.
//
// Wire in via a `job_boards:` entry with `provider: jobspresso`.
const FEED_URL = 'https://jobspresso.co/?feed=job_feed';
const TRUSTED_HOST = 'jobspresso.co';
/** @param {string} url */
function assertJobspressoUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`jobspresso: invalid URL: ${url}`);
}
if (parsed.protocol !== "https:")
throw new Error(`jobspresso: URL must use HTTPS: ${url}`);
if (parsed.hostname !== TRUSTED_HOST) {
throw new Error(
`jobspresso: 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;
}
/** @type {Provider} */
export default {
id: "jobspresso",
detect(entry) {View on GitHub (pinned to 9b17a8ac97)
Solutions
- Keep FEED_URL on the bare jobspresso.co host, or if a subdomain is genuinely required, update the assert to allow *.jobspresso.co.
- Never route untrusted entry input through assertJobspressoUrl without confirming the host.
- Document any allowlist change next to TRUSTED_HOST.
Example fix
// before (strict — rejects subdomains)
if (parsed.hostname !== TRUSTED_HOST) { throw ... }
// after (allow subdomains)
if (parsed.hostname !== TRUSTED_HOST && !parsed.hostname.endsWith('.' + TRUSTED_HOST)) { throw ... } Defensive patterns
Strategy: validation
Validate before calling
const TRUSTED_HOST = 'jobspresso.co';
function isTrustedJobspressoHost(url) {
const u = new URL(url);
return u.hostname === TRUSTED_HOST; // assert is strict — subdomains NOT allowed
} Type guard
/** True for a URL on exactly jobspresso.co (no subdomains, per the assert). */
function isJobspressoTrusted(url) {
try {
const u = new URL(url);
return u.protocol === 'https:' && u.hostname === 'jobspresso.co';
} catch { return false; }
} Try / catch
try {
return await jobspressoProvider.fetch(entry, ctx);
} catch (err) {
if (/untrusted hostname/.test(err.message)) {
console.error(`jobspresso: host not allowlisted — ${err.message}`);
}
throw err;
} Prevention
- Keep FEED_URL on the bare jobspresso.co host; widen the allowlist deliberately if a subdomain is truly needed.
- Treat the SSRF allowlist as load-bearing — never widen it casually.
- Do not route untrusted entry input through the assert.
When it happens
Trigger: Editing FEED_URL to a different host (a CDN/mirror); reusing assertJobspressoUrl on entry input pointing at a subdomain like feed.jobspresso.co; an attempt to route the request off-host via a crafted URL.
Common situations: Switching to a subdomain endpoint and assuming the assert allows it; a fork adding a configurable host without widening the allowlist; malicious/typo entry input routed through the assert.
Related errors
- himalayas: untrusted hostname "${parsed.hostname}" - must be
- jobspresso: invalid URL: ${url}
- jobspresso: URL must use HTTPS: ${url}
- comeet: invalid URL: ${redactToken(url)}
- comeet: URL must use HTTPS: ${redactToken(url)}
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/cb468dfcdc20e1f9.
Report an issue: GitHub.