{"record":{"id":"2d24a76fc157b0b6","repo":"ruvnet/ruflo","slug":"forbidden-header","errorCode":"FORBIDDEN_HEADER","errorMessage":"header \"${key}\" is not allowed without CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH=1","messagePattern":"header \"(.+?)\" is not allowed without CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH=1","errorType":"validation","errorClass":"HttpFetchValidationError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/mcp-tools/http-fetch-tools.ts","lineNumber":103,"sourceCode":"    if (a === 169 && b === 254) return true;          // link-local\n    if (a === 100 && b >= 64 && b <= 127) return true; // CGNAT\n    return false;\n  }\n  // IPv6 bracketed addresses and other special forms — be conservative and\n  // accept only public-looking literals. Reject obvious private/local forms.\n  if (host.startsWith('fc') || host.startsWith('fd')) return true;  // fc00::/7 ULA\n  if (host.startsWith('fe80:')) return true;                        // link-local\n  return false;\n}\n\nexport function validateHeaders(headers: Record<string, string>): Record<string, string> {\n  const allowAuth = process.env.CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH === '1';\n  const out: Record<string, string> = {};\n  for (const [key, value] of Object.entries(headers)) {\n    const lower = key.toLowerCase();\n    if (!allowAuth) {\n      if ((FORBIDDEN_HEADERS_EXACT as readonly string[]).includes(lower)) {\n        throw new HttpFetchValidationError(\n          `header \"${key}\" is not allowed without CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH=1`,\n          'FORBIDDEN_HEADER',\n        );\n      }\n      if (FORBIDDEN_HEADER_PREFIXES.some((p) => lower.startsWith(p))) {\n        throw new HttpFetchValidationError(\n          `header \"${key}\" is not allowed without CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH=1`,\n          'FORBIDDEN_HEADER',\n        );\n      }\n    }\n    if (typeof value !== 'string') {\n      throw new HttpFetchValidationError(\n        `header \"${key}\" must be a string`,\n        'INVALID_HEADER_VALUE',\n      );\n    }\n    out[key] = value;","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/cli/src/mcp-tools/http-fetch-tools.ts#L85-L121","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nhttp_fetch({ url, headers: { authorization: `Bearer ${token}` } })  // throws\n// after\n// env: export CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH=1\nhttp_fetch({ url, headers: { authorization: `Bearer ${token}` } })","handlingStrategy":"validation","validationCode":"const EXACT = new Set(['authorization','cookie','set-cookie','proxy-authorization']);\nfunction assertHeadersAllowed(headers, allowAuth = process.env.CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH === '1') {\n  if (!allowAuth) for (const k of Object.keys(headers)) {\n    if (EXACT.has(k.toLowerCase())) throw new Error(`header ${k} requires CLAUDE_FLOW_HTTP_FETCH_ALLOW_AUTH=1`);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["http-fetch","security","headers","auth","validation"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}