ruvnet/ruflo · error · HttpFetchValidationError
FORBIDDEN_HEADER
FORBIDDEN_HEADER
Error message
header "${key}" is not allowed without CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH=1 What it means
Thrown by validateHeaders in the http_fetch tool when a header name exactly matches the auth-bearing blocklist FORBIDDEN_HEADERS_EXACT (authorization, cookie, set-cookie, proxy-authorization) and CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH is not '1'. This default prevents credential pass-through to potentially untrusted endpoints. The error carries code FORBIDDEN_HEADER.
Source
Thrown at v3/@claude-flow/cli/src/mcp-tools/http-fetch-tools.ts:103
if (a === 169 && b === 254) return true; // link-local
if (a === 100 && b >= 64 && b <= 127) return true; // CGNAT
return false;
}
// IPv6 bracketed addresses and other special forms — be conservative and
// accept only public-looking literals. Reject obvious private/local forms.
if (host.startsWith('fc') || host.startsWith('fd')) return true; // fc00::/7 ULA
if (host.startsWith('fe80:')) return true; // link-local
return false;
}
export function validateHeaders(headers: Record<string, string>): Record<string, string> {
const allowAuth = process.env.CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH === '1';
const out: Record<string, string> = {};
for (const [key, value] of Object.entries(headers)) {
const lower = key.toLowerCase();
if (!allowAuth) {
if ((FORBIDDEN_HEADERS_EXACT as readonly string[]).includes(lower)) {
throw new HttpFetchValidationError(
`header "${key}" is not allowed without CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH=1`,
'FORBIDDEN_HEADER',
);
}
if (FORBIDDEN_HEADER_PREFIXES.some((p) => lower.startsWith(p))) {
throw new HttpFetchValidationError(
`header "${key}" is not allowed without CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH=1`,
'FORBIDDEN_HEADER',
);
}
}
if (typeof value !== 'string') {
throw new HttpFetchValidationError(
`header "${key}" must be a string`,
'INVALID_HEADER_VALUE',
);
}
out[key] = value;View on GitHub (pinned to 6b01dc5a68)
Solutions
- Set CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH=1 in the environment when credential headers are intentional and the target is trusted.
- Prefer a server-side proxy that injects credentials rather than passing them through the fetch tool.
- Confirm the target endpoint truly requires the header; some APIs accept query-param or mTLS auth instead.
- Never set ALLOW_AUTH=1 together with untrusted/external URLs — it leaks credentials.
Example fix
// before
http_fetch({ url, headers: { authorization: `Bearer ${token}` } }) // throws
// after
// env: export CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH=1
http_fetch({ url, headers: { authorization: `Bearer ${token}` } }) Defensive patterns
Strategy: validation
Validate before calling
const EXACT = new Set(['authorization','cookie','set-cookie','proxy-authorization']);
function assertHeadersAllowed(headers, allowAuth = process.env.CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH === '1') {
if (!allowAuth) for (const k of Object.keys(headers)) {
if (EXACT.has(k.toLowerCase())) throw new Error(`header ${k} requires CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH=1`);
}
} Prevention
- Set CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH=1 only for trusted targets.
- Prefer a server-side proxy injecting credentials.
- Never combine ALLOW_AUTH with untrusted URLs.
When it happens
Trigger: Passing headers containing (case-insensitive) 'authorization', 'cookie', 'set-cookie', or 'proxy-authorization' without setting CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH=1. Header names are lowercased before the exact-match check.
Common situations: Adding an Authorization: Bearer <token> for an authenticated API; forwarding session cookies; using a proxy that requires proxy-authorization; calling an internal API that mandates an auth header.
Related errors
- FORBIDDEN_PROTOCOL
- PRIVATE_ADDRESS
- INVALID_HEADER_VALUE
- INVALID_HEADERS
- Validation failed: ${result.error}
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/2d24a76fc157b0b6.
Report an issue: GitHub.