--- django/http/request.py	2026-03-27 07:18:59.492226216 +0000
+++ django/http/request.py	2026-03-27 07:31:17.268673806 +0000
@@ -1,7 +1,7 @@
-import cgi
 import codecs
 import copy
 import warnings
+from email.message import Message
 from io import BytesIO
 from itertools import chain
 from urllib.parse import parse_qsl, quote, urlencode, urljoin, urlsplit
@@ -102,7 +102,10 @@
 
     def _set_content_type_params(self, meta):
         """Set content_type, content_params, and encoding."""
-        self.content_type, self.content_params = cgi.parse_header(meta.get('CONTENT_TYPE', ''))
+        msg = Message()
+        msg['content-type'] = meta.get('CONTENT_TYPE', '')
+        self.content_type = msg.get_content_type()
+        self.content_params = dict(msg.get_params()[1:])
         if 'charset' in self.content_params:
             try:
                 codecs.lookup(self.content_params['charset'])
--- django/http/multipartparser.py	2026-03-27 07:18:59.492065683 +0000
+++ django/http/multipartparser.py	2026-03-27 09:11:06.438253201 +0000
@@ -6,7 +6,6 @@
 """
 import base64
 import binascii
-import cgi
 import collections
 import html
 from urllib.parse import unquote
@@ -21,6 +20,7 @@
 )
 from django.utils.datastructures import MultiValueDict
 from django.utils.encoding import force_str
+from django.utils.regex_helper import _lazy_re_compile
 
 __all__ = ('MultiPartParser', 'MultiPartParserError', 'InputStreamExhausted')
 
@@ -49,6 +49,9 @@
     ``MultiValueDict.parse()`` reads the input stream in ``chunk_size`` chunks
     and returns a tuple of ``(MultiValueDict(POST), MultiValueDict(FILES))``.
     """
+
+    boundary_re = _lazy_re_compile(r"[ -~]{0,200}[!-~]")
+
     def __init__(self, META, input_data, upload_handlers, encoding=None):
         """
         Initialize the MultiPartParser object.
@@ -74,7 +77,9 @@
         except UnicodeEncodeError:
             raise MultiPartParserError('Invalid non-ASCII Content-Type in multipart: %s' % force_str(content_type))
         boundary = opts.get('boundary')
-        if not boundary or not cgi.valid_boundary(boundary):
+        if isinstance(boundary, bytes):
+            boundary = boundary.decode('ascii')
+        if not boundary or not self.boundary_re.fullmatch(boundary):
             raise MultiPartParserError('Invalid boundary in multipart: %s' % force_str(boundary))
 
         # Content-Length should contain the length of the body we are about
