{"record":{"id":"1aa98f9eb00ca4f1","repo":"aio-libs/aiohttp","slug":"invalid-default-charset","errorCode":null,"errorMessage":"Invalid default charset","messagePattern":"Invalid default charset","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"aiohttp/multipart.py","lineNumber":775,"sourceCode":"            await self._read_boundary()\n        if self._at_eof:  # we just read the last boundary, nothing to do there\n            # https://github.com/python/mypy/issues/17537\n            return None  # type: ignore[unreachable]\n\n        part = await self.fetch_next_part()\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.6\n        if (\n            self._last_part is None\n            and self._mimetype.subtype == \"form-data\"\n            and isinstance(part, BodyPartReader)\n        ):\n            _, params = parse_content_disposition(part.headers.get(CONTENT_DISPOSITION))\n            if params.get(\"name\") == \"_charset_\":\n                # Longest encoding in https://encoding.spec.whatwg.org/encodings.json\n                # is 19 characters, so 32 should be more than enough for any valid encoding.\n                charset = await part.read_chunk(32)\n                if len(charset) > 31:\n                    raise RuntimeError(\"Invalid default charset\")\n                self._default_charset = charset.strip().decode()\n                part = await self.fetch_next_part()\n        self._last_part = part\n        return self._last_part\n\n    async def release(self) -> None:\n        \"\"\"Reads all the body parts to the void till the final boundary.\"\"\"\n        while not self._at_eof:\n            item = await self.next()\n            if item is None:\n                break\n            await item.release()\n\n    async def fetch_next_part(\n        self,\n    ) -> Union[\"MultipartReader\", BodyPartReader]:\n        \"\"\"Returns the next body part reader.\"\"\"\n        headers = await self._read_headers()","sourceCodeStart":757,"sourceCodeEnd":793,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/multipart.py#L757-L793","documentation":"In form-data processing, if the first part's field name is '_charset_', the reader treats its value as the default charset for subsequent parts. To prevent unbounded charset injection it reads at most 32 bytes; if the value exceeds 31 bytes, RuntimeError 'Invalid default charset' is raised.","triggerScenarios":"A multipart/form-data request whose first part is named '_charset_' and whose value (the declared charset) is 32 or more bytes long.","commonSituations":"Malicious or malformed requests exploiting the RFC 7578 _charset_ convention to inject a huge string; buggy producer writing the field name as the charset value.","solutions":["Reject/validate multipart/form-data requests where the _charset_ field value exceeds a sane length (e.g. 31 bytes) before parsing.","Ensure your producer only ever writes a real encoding label (utf-8, iso-8859-1, etc.) into _charset_.","Catch RuntimeError around reader.next() and respond 400 Bad Request.","Cap request body size and field sizes upstream so abuse is bounded."],"exampleFix":"// before\nfield name=\"_charset_\"\nvalue = b\"utf-8-very-long-invalid-label-xxxxxxxxxxxx\"\n\n// after\nfield name=\"_charset_\"\nvalue = b\"utf-8\"","handlingStrategy":"validation","validationCode":"MAX_CHARSET_LEN = 31\n\nasync def safe_next(reader):\n    part = await reader.next()\n    if (\n        isinstance(part, BodyPartReader)\n        and part.name == '_charset_'\n    ):\n        probe = await part.read_chunk(MAX_CHARSET_LEN + 1)\n        if len(probe) > MAX_CHARSET_LEN:\n            raise web.HTTPBadRequest(text='_charset_ value too long')\n        part.unread_data(probe)\n    return part","typeGuard":"def is_valid_charset_label(raw: bytes) -> bool:\n    return 0 < len(raw) <= 31 and raw.strip().isascii()","tryCatchPattern":"try:\n    part = await reader.next()\nexcept RuntimeError as e:\n    if 'Invalid default charset' in str(e):\n        return web.Response(status=400, text='Malformed _charset_ field')\n    raise","preventionTips":["Validate field names and sizes before parsing multipart/form-data.","Only ever write a real encoding label into the _charset_ field on the producer side.","Cap body and field sizes at the reverse proxy."],"tags":["multipart","form-data","charset","security","input-validation"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}