{"record":{"id":"4481695be120fc5a","repo":"aio-libs/aiohttp","slug":"too-many-headers-received-448169","errorCode":null,"errorMessage":"Too many headers received","messagePattern":"Too many headers received","errorType":"http","errorClass":"BadHttpMessage","httpStatus":400,"severity":"error","filePath":"aiohttp/multipart.py","lineNumber":894,"sourceCode":"                self._unread.append(next_line)\n            # otherwise the request is likely missing an epilogue and both\n            # lines should be passed to the parent for processing\n            # (this handles the old behavior gracefully)\n            else:\n                self._unread.extend([next_line, epilogue])\n        else:\n            raise ValueError(f\"Invalid boundary {chunk!r}, expected {self._boundary!r}\")\n\n    async def _read_headers(self) -> HeadersDictProxy:\n        lines = []\n        while True:\n            chunk = await self._content.readline(max_line_length=self._max_field_size)\n            chunk = chunk.rstrip(b\"\\r\\n\")\n            lines.append(chunk)\n            if not chunk:\n                break\n            if len(lines) > self._max_headers:\n                raise BadHttpMessage(\"Too many headers received\")\n        parser = HeadersParser(max_field_size=self._max_field_size)\n        headers, _ = parser.parse_headers(lines)\n        return headers\n\n    async def _maybe_release_last_part(self) -> None:\n        \"\"\"Ensures that the last read body part is read completely.\"\"\"\n        if self._last_part is not None:\n            if not self._last_part.at_eof():\n                await self._last_part.release()\n            self._unread.extend(self._last_part._unread)\n            self._last_part = None\n\n\n_Part = tuple[Payload, str, str]\n\n\nclass MultipartWriter(Payload):\n    \"\"\"Multipart body writer.\"\"\"","sourceCodeStart":876,"sourceCodeEnd":912,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/multipart.py#L876-L912","documentation":"_read_headers reads header lines of a body part until a blank line, but caps the count at max_headers (default 128). Surpassing the cap raises BadHttpMessage 'Too many headers received' to prevent unbounded memory use (header-flood DoS).","triggerScenarios":"A single multipart body part whose header block contains more than max_headers lines before the terminating blank line; e.g. hundreds of Content-Disposition lines or a missing blank-line terminator causing the parser to consume boundary lines as headers.","commonSituations":"Missing CRLF CRLF terminator after part headers (parser keeps reading); malicious header flooding; a part generated by a loop that emits a header per iteration; under-sized max_headers configured by the application.","solutions":["Ensure each part's header block ends with a blank line ('\\r\\n\\r\\n').","Reduce the number of headers per part to well under 128, or pass a higher max_headers to MultipartReader if legitimately needed.","Reject requests with abnormally large header blocks at the web server/reverse-proxy layer (client_max_body_size, large_client_header_buffers equivalents).","Catch BadHttpMessage and respond 431/400."],"exampleFix":"// before\nreader = MultipartReader(response.headers, response.content)  # default max_headers=128\n\n// after\nreader = MultipartReader(response.headers, response.content, max_headers=1024)","handlingStrategy":"validation","validationCode":"DEFAULT_MAX_HEADERS = 128\n\ndef reader_with_caps(headers, content, *, max_headers=DEFAULT_MAX_HEADERS):\n    return MultipartReader(headers, content, max_headers=max_headers,\n                           max_field_size=8190)\n\n# at the request edge, reject parts with absurdly many headers up front\nif request.headers.get('Content-Length', 0, type=int) > BODY_CAP:\n    return web.Response(status=413, text='Payload too large')","typeGuard":null,"tryCatchPattern":"from aiohttp.http_exceptions import BadHttpMessage\ntry:\n    reader = MultipartReader(request.headers, request.content, max_headers=1024)\n    async for part in reader:\n        process(part)\nexcept BadHttpMessage as e:\n    if 'Too many headers' in str(e):\n        return web.Response(status=431, text='Too many headers in multipart part')\n    raise","preventionTips":["Ensure each part's header block ends with a blank line (CRLF CRLF).","Pass an explicit max_headers sized to your legitimate use case.","Cap body/header sizes at the reverse proxy to bound abuse."],"tags":["multipart","headers","dos-protection","limits","badhttpmessage"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}