{"record":{"id":"95080d6d431506ca","repo":"mihomo-party-org/clash-party","slug":"forbidden-header-k","errorCode":null,"errorMessage":"Forbidden header: ${k}","messagePattern":"Forbidden header: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/main/resolve/plugin/http-client.ts","lineNumber":38,"sourceCode":"  headers: http.IncomingHttpHeaders\n  body: string\n}\n\nconst FORBIDDEN_HEADERS = new Set(['host', 'content-length', 'connection', 'transfer-encoding'])\nconst MAX_HEADERS = 32\nconst MAX_HEADER_NAME_LEN = 128\nconst MAX_HEADER_VALUE_LEN = 4096\nconst MAX_HEADER_BYTES = 16 * 1024\n\nfunction validateHeaders(input: Record<string, string>): Record<string, string> {\n  const entries = Object.entries(input)\n  if (entries.length > MAX_HEADERS) throw new Error('Request headers too large')\n\n  const headers: Record<string, string> = {}\n  let total = 0\n  for (const [k, v] of entries) {\n    if (FORBIDDEN_HEADERS.has(k.toLowerCase())) {\n      throw new Error(`Forbidden header: ${k}`)\n    }\n    const nameBytes = Buffer.byteLength(k, 'utf-8')\n    const valueBytes = Buffer.byteLength(v, 'utf-8')\n    if (nameBytes > MAX_HEADER_NAME_LEN || valueBytes > MAX_HEADER_VALUE_LEN) {\n      throw new Error('Request headers too large')\n    }\n    total += nameBytes + valueBytes\n    headers[k] = v\n  }\n  if (total > MAX_HEADER_BYTES) throw new Error('Request headers too large')\n  return headers\n}\n\nexport function requestOnce(urlStr: string, opts: PluginRequestOptions): Promise<PluginResponse> {\n  return new Promise((resolve, reject) => {\n    let url: URL\n    try {\n      url = new URL(urlStr)","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/mihomo-party-org/clash-party/blob/911e090537acdf7c50bee1c3aebecc2ef119a8b5/src/main/resolve/plugin/http-client.ts#L20-L56","documentation":"validateHeaders() rejects requests containing headers in the FORBIDDEN_HEADERS set (matched case-insensitively). These headers (typically hop-by-hop or identity/spoofable ones like host, content-length, connection, cookie controls) must be controlled by the HTTP client itself, so user-supplied values are rejected with `Forbidden header: ${k}`.","triggerScenarios":"Passing any header whose lowercase name is in FORBIDDEN_HEADERS — e.g. { 'Host': 'x', 'content-length': '5', 'Connection': 'keep-alive' } — in the headers argument consumed by requestOnce.","commonSituations":"Blindly forwarding headers from an inbound request (host, connection, content-length are common), manually setting content-length after the client already computes it, or copying headers from a cURL example that includes forbidden ones.","solutions":["Remove the forbidden header(s) from the headers object before calling.","If forwarding inbound headers, filter against the forbidden set (case-insensitive) first.","Let the client set transport-level headers (host, content-length, connection) itself; only pass application-level headers."],"exampleFix":"// before\nawait request(url, { headers: { host: 'gw.example', 'content-type': 'application/json' } })\n// after\nawait request(url, { headers: { 'content-type': 'application/json' } })","handlingStrategy":"validation","validationCode":"const FORBIDDEN = new Set(['host','content-length','connection','transfer-encoding','expect','keep-alive'])\nconst safeHeaders = Object.fromEntries(\n  Object.entries(headers).filter(([k]) => !FORBIDDEN.has(k.toLowerCase()))\n)","typeGuard":null,"tryCatchPattern":"try {\n  return await request(url, { headers })\n} catch (e) {\n  const m = (e as Error).message.match(/^Forbidden header: (.+)$/)\n  if (m) {\n    delete headers[m[1]]\n    return request(url, { headers })\n  } else throw e\n}","preventionTips":["Never forward inbound request headers wholesale; filter hop-by-hop/transport headers first.","Let the HTTP client manage host, content-length, and connection headers.","Keep a shared FORBIDDEN_HEADERS list in sync when the library updates it."],"tags":["http","headers","validation","security"],"backgroundTag":"forbidden-header","analyzedSha":"911e090537acdf7c50bee1c3aebecc2ef119a8b5","analyzedAt":"2026-08-30T13:00:49.174Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}