santifer/career-ops · error · Error
recruitee: untrusted hostname
Error message
recruitee: untrusted hostname "${parsed.hostname}" — must match <slug>.recruitee.com What it means
The Recruitee API may only be called on <slug>.recruitee.com hosts; this is the provider's SSRF defence, since the fetched URL is server-side requested. Any hostname not matching the /^\[a-z0-9\]\[a-z0-9-\]*\.recruitee\.com$/ regex (custom domains, lookalike hosts, bare domains) is rejected.
Solutions
- Resolve the custom domain to its underlying <slug>.recruitee.com host and configure that as careers_url
- Check the DNS/CNAME of the custom domain — it usually aliases <slug>.recruitee.com
- Ensure the slug uses only lowercase letters, digits and hyphens and is a single label under recruitee.com
- If the board is genuinely not on recruitee.com, this provider does not apply — use the correct provider
Example fix
// before careers_url: https://careers.hostaway.com // after careers_url: https://hostaway.recruitee.com
Defensive patterns
Strategy: validation
Validate before calling
const RE = /^[a-z0-9][a-z0-9-]*\.recruitee\.com$/;
function isRecruiteeHost(s) {
try { return RE.test(new URL(s).hostname); } catch { return false; }
}
if (!isRecruiteeHost(entry.careers_url)) throw new Error(`Resolve custom domain to <slug>.recruitee.com for ${entry.name}`); Type guard
function isRecruiteeTenantUrl(v) {
try {
const u = new URL(String(v));
return u.protocol === 'https:' && /^[a-z0-9][a-z0-9-]*\.recruitee\.com$/.test(u.hostname);
} catch { return false; }
} Try / catch
try {
assertRecruiteeUrl(entry.careers_url);
} catch (err) {
const m = err.message.match(/untrusted hostname "([^"]+)"/);
if (m) console.error(`Host ${m[1]} is not *.recruitee.com — resolve its CNAME to find the tenant slug`);
throw err;
} Prevention
- Resolve custom careers domains (dig CNAME) to the underlying <slug>.recruitee.com and configure that
- Never configure proxies, mirrors, or non-recruitee.com hosts for this provider
- Remember the guard is an SSRF defence — only single-label slugs under recruitee.com pass
When it happens
Trigger: A careers_url pointing at a custom careers domain (careers.example.com), a different tenant host, a subdomain of recruitee.com deeper than one label, or uppercase/invalid slug characters reaches assertRecruiteeUrl.
Common situations: A company serves its Recruitee board behind its own domain (very common — e.g. careers.hostaway.com) while the config stores only that custom URL; someone configures a proxy or mirror host; a typo like acme.recruitee.com.evil.io.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- Access denied: Localhost or internal domain target detected.
- agentic-jobs: untrusted hostname
- eightfold: untrusted hostname
- landingjobs: untrusted hostname
- larajobs: untrusted hostname
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/94a4625f7a9fa49d.
Report an issue: GitHub.
Appendix: source
Thrown at providers/recruitee.mjs:23
// Auto-detects from careers_url pattern `https://<slug>.recruitee.com`.
// Per-tenant subdomains are the variable part — SSRF defence uses a
// regex match on `<safe-slug>.recruitee.com` rather than a static
// allowlist.
import { htmlToText } from './_html-to-text.mjs';
const RECRUITEE_HOST_RE = /^[a-z0-9][a-z0-9-]*\.recruitee\.com$/;
function assertRecruiteeUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`recruitee: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`recruitee: URL must use HTTPS: ${url}`);
if (!RECRUITEE_HOST_RE.test(parsed.hostname)) {
throw new Error(`recruitee: untrusted hostname "${parsed.hostname}" — must match <slug>.recruitee.com`);
}
return url;
}
function resolveApiUrl(entry) {
const raw = typeof entry.careers_url === 'string' ? entry.careers_url : '';
if (!raw) return null;
let parsed;
try {
parsed = new URL(raw);
} catch {
return null;
}
if (parsed.protocol !== 'https:') return null;
if (!RECRUITEE_HOST_RE.test(parsed.hostname)) return null;
return `https://${parsed.hostname}/api/offers/`;
}
View on GitHub (pinned to aac998c7ed)