diff --git a/src/saml2/httputil.py b/src/saml2/httputil.py
index 3ad668b71..c7abc6fdd 100644
--- a/src/saml2/httputil.py
+++ b/src/saml2/httputil.py
@@ -1,4 +1,3 @@
-import cgi
 import hashlib
 import hmac
 from http.cookies import SimpleCookie
@@ -182,7 +181,10 @@ def extract(environ, empty=False, err=False):
     :param empty: Stops on empty fields (default: Fault)
     :param err: Stops on errors in fields (default: Fault)
     """
-    formdata = cgi.parse(environ["wsgi.input"], environ, empty, err)
+    input_stream = environ["wsgi.input"]
+    content_length = int(environ.get("CONTENT_LENGTH", 0))
+    input_data = input_stream.read(content_length).decode('utf-8')
+    formdata = parse_qs(input_data)
     # Remove single entries from lists
     for key, value in iter(formdata.items()):
         if len(value) == 1:
diff --git a/src/saml2/pack.py b/src/saml2/pack.py
index 99c32476b..cee1cf1c8 100644
--- a/src/saml2/pack.py
+++ b/src/saml2/pack.py
@@ -8,14 +8,9 @@
 """
 
 import base64
-
-
-try:
-    import html
-except Exception:
-    import cgi as html  # type: ignore[no-redef]
-
+import html
 import logging
+
 from urllib.parse import urlencode
 from urllib.parse import urlparse
 from xml.etree import ElementTree as ElementTree
diff --git a/src/saml2/server.py b/src/saml2/server.py
index 8b5572001..2ee4c301f 100644
--- a/src/saml2/server.py
+++ b/src/saml2/server.py
@@ -4,6 +4,7 @@
 """Contains classes and functions that a SAML2.0 Identity provider (IdP)
 or attribute authority (AA) may use to conclude its tasks.
 """
+import sys
 import dbm
 import importlib
 import logging
@@ -57,7 +58,12 @@
 
 def _shelve_compat(name, *args, **kwargs):
     try:
-        return shelve.open(name, *args, **kwargs)
+        if sys.version_info < (3, 13):
+            return shelve.open(name, *args, **kwargs)
+        else:
+            # Python 3.13 and later uses dbm.sqlite3 as default which is not compatible
+            # with cheroot using threading. So, we need to use dbm.dumb instead.
+            return shelve.Shelf(dbm.dumb.open(name), *args, **kwargs)
     except dbm.error[0]:
         # Python 3 whichdb needs to try .db to determine type
         if name.endswith(".db"):