angular/angular-cli · error · Error

Header "${headerName}" with value "${headerValue}" is not al

Error message

Header "${headerName}" with value "${headerValue}" is not allowed.

What it means

Angular SSR validates the `host` and `x-forwarded-host` headers against an allowlist of trusted hostnames to prevent host header injection attacks (cache poisoning, password-reset poisoning). When `verifyHostAllowed` is called from `validateHeaders` and the hostname is not in `allowedHosts`, the request is rejected with this error naming the header and value.

Source

Thrown at packages/angular/ssr/src/utils/validation.ts:152

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;
  }

  for (const allowedHost of allowedHosts) {
    if (!allowedHost.startsWith('*.')) {
      continue;
    }

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Add the offending hostname to the `allowedHosts` list in the Angular SSR server configuration.
  2. Access the app using a hostname that is already allowlisted (e.g. configured custom domain instead of raw IP).
  3. If the host header comes from a trusted proxy, trust/forward it correctly (configure `trustProxyHeaders` and the proxy's X-Forwarded-Host) so validation sees the right value.
  4. If a proxy strips the host, configure the proxy to pass the original Host/X-Forwarded-Host headers.

Example fix

// before
serverContextConfig = { allowedHosts: ['localhost'] };
// after
serverContextConfig = { allowedHosts: ['localhost', 'myapp.example.com'] };
Defensive patterns

Strategy: validation

Validate before calling

const allowed = new Set(['localhost', 'myapp.example.com']);
const host = new URL(request.url).hostname;
if (!allowed.has(host)) throw new Error(`Refusing request for host "${host}"; add it to allowedHosts.`);

Try / catch

try {
  await handleRequest(req);
} catch (e) {
  if ((e as Error).message.includes('is not allowed')) {
    res.status(403).end('Host not allowed');
  } else { throw e; }
}

Prevention

When it happens

Trigger: A request reaches the SSR server whose `host` or `x-forwarded-host` header (or the `forwarded` header's `host` parameter) resolves to a hostname not present in the configured allowedHosts set.

Common situations: Accessing a locally served app via 127.0.0.1 or LAN IP while localhost is the only allowed host; deploying behind a proxy/CDN that rewrites the Host header; forgetting to add a staging/custom domain to allowedHosts for SSR (`allowedHosts` / `allowedHostsHeader` server config).

Related errors


AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30). Data as JSON: /api/errors/6b782800c0eda56f. Report an issue: GitHub.