angular/angular-cli · error · Error
Header "${headerName}" with value "${headerValue}" contains
Error message
Header "${headerName}" with value "${headerValue}" contains characters that are not allowed. What it means
After parsing the forwarded-host header value, verifyHostAllowed rejects values that contain more than a bare hostname: a non-empty path, query, hash, or credentials in 'http://<value>' indicate the header is not a plain host and could be an injection attempt, so the request is rejected.
Source
Thrown at packages/angular/ssr/src/utils/validation.ts:146
*
* @param headerName - The name of the header to validate (e.g., 'host', 'x-forwarded-host').
* @param headerValue - The value of the header to validate.
* @param allowedHosts - A set of allowed hostnames.
* @throws Error if the header value is invalid or the hostname is not in the allowlist.
*/
function verifyHostAllowed(
headerName: string,
headerValue: string,
allowedHosts: ReadonlySet<string>,
): void {
const url = `http://${headerValue}`;
if (!URL.canParse(url)) {
throw new Error(`Header "${headerName}" contains an invalid value and cannot be parsed.`);
}
const { hostname, pathname, search, hash, username, password } = new URL(url);
if (pathname !== '/' || search || hash || username || password) {
throw new Error(
`Header "${headerName}" with value "${headerValue}" contains characters that are not allowed.`,
);
}
if (!isHostAllowed(hostname, allowedHosts)) {
throw new Error(`Header "${headerName}" with value "${headerValue}" is not allowed.`);
}
}
/**
* Checks if the hostname is allowed.
* @param hostname - The hostname to check.
* @param allowedHosts - A set of allowed hostnames.
* @returns `true` if the hostname is allowed, `false` otherwise.
*/
function isHostAllowed(hostname: string, allowedHosts: ReadonlySet<string>): boolean {
if (allowedHosts.has('*') || allowedHosts.has(hostname)) {
return true;View on GitHub (pinned to bb72145f9a)
Solutions
- Configure the upstream proxy to emit only the bare hostname in X-Forwarded-Host (e.g. nginx: proxy_set_header X-Forwarded-Host $host;).
- Strip path/query/credentials from the header value before forwarding.
- Identify the requesting client from logs and block/fix the source of the malformed header.
Example fix
// before (nginx) proxy_set_header X-Forwarded-Host $request_uri; // after proxy_set_header X-Forwarded-Host $host;
Defensive patterns
Strategy: validation
Validate before calling
const fwh = request.headers.get('x-forwarded-host');
if (fwh) {
const u = new URL(`http://${fwh}`);
if (u.pathname !== '/' || u.search || u.hash || u.username || u.password) {
return new Response('Bad Request', { status: 400 });
}
} Type guard
function isBareHostValue(value: string): boolean {
const u = new URL(`http://${value}`);
return u.pathname === '/' && !u.search && !u.hash && !u.username && !u.password;
} Try / catch
try {
await render(request);
} catch (e) {
if (e instanceof Error && e.message.includes('contains characters that are not allowed.')) {
return new Response('Bad Request: invalid forwarded host', { status: 400 });
} throw e;
} Prevention
- Configure proxies with proxy_set_header X-Forwarded-Host $host so only the bare hostname is forwarded.
- Never copy the full request URI into host headers in custom middleware.
- Treat violations as potential host-header-injection probes and alert/log them.
When it happens
Trigger: X-Forwarded-Host (or similar) values like 'example.com/evil', 'example.com?q=1', 'user:pass@example.com', or 'example.com#frag' — anything where pathname !== '/', or search/hash/username/password are non-empty.
Common situations: Proxies forwarding the full original URL in X-Forwarded-Host; attackers probing for host-header injection; misconfigured middleware copying the entire request URL into the header.
Related errors
- Header "${headerName}" contains an invalid value and cannot
- URL with hostname "${hostname}" is not allowed.
- Header "${headerName}" with value "${headerValue}" is not al
- Header "forwarded" proto parameter must be either "http" or
- Header "x-forwarded-port" must be a numeric value.
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/5b936667f2b1f7d5.
Report an issue: GitHub.