{"id":"CVE-2026-101918","aliases":["AZL-105218","BELL-CVE-2026-101918","CLSA-2026-1791271338","CLSA-2026-1791272473","CLSA-2026-1791272714","DEBIAN-CVE-2026-101918","EUVD-2026-88479","GHSA-42vr-xj54-vc7v","OESA-2026-4453","OESA-2026-4454","OESA-2026-4455","OESA-2026-4456","PYSEC-2026-4141","SUSE-SU-2026:24126-1","SUSE-SU-2026:24134-1","SUSE-SU-2026:24219-1","SUSE-SU-2026:24377-1","SUSE-SU-2026:5064-1","UBUNTU-CVE-2026-101918","USN-8934-1","openSUSE-SU-2026:11994-1","openSUSE-SU-2026:22074-1"],"status":"published","title":"PyJWT: Unauthenticated RecursionError DoS in pre-verification payload parse (PyJWKClient.get_signing_key_from_jwt / verify_signature=False)","description":"PyJWT is a Python implementation of JSON Web Token standards. From 2.0.0a1 until 2.15.0, PyJWT PyJWKClient.get_signing_key_from_jwt is affected because payload parser catches ValueError but not RecursionError. This occurs when an attacker-controlled recursively nested payload reaches json.loads. As a result, documented PyJWT exception handling does not contain the failure. Consequently, an unauthenticated request can raise an exception that may produce an HTTP 500 response. The advisory-defined affected implementation also includes jwt/api_jwt.py, verify_signature=False. This issue is fixed in version 2.15.0.","severity":{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-10","score":0.00413,"percentile":0.35915,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-248"],"published":"2026-09-28T20:11:55Z","modified":"2026-11-07T07:15:04Z","fixes":[{"ecosystem":"PyPI","package":"pyjwt","fixed_in":["2.15.0"],"sources":["ghsa","osv"]},{"ecosystem":"Azure Linux:3","package":"python-jwt","fixed_in":["2.15.1-1"],"sources":["osv"]},{"ecosystem":"Alpaquita:25","package":"py3-jwt","fixed_in":["2.15.1-r0"],"sources":["osv"]},{"ecosystem":"Alpaquita:stream","package":"py3-jwt","fixed_in":["2.15.1-r0"],"sources":["osv"]},{"ecosystem":"Debian:14","package":"pyjwt","fixed_in":["2.15.0-1"],"sources":["osv"]},{"ecosystem":"Ubuntu:Pro:16.04:LTS","package":"pyjwt","fixed_in":["1.3.0-1ubuntu0.1+esm4"],"sources":["osv"]},{"ecosystem":"Ubuntu:Pro:18.04:LTS","package":"pyjwt","fixed_in":["1.5.3+ds1-1ubuntu0.1+esm4"],"sources":["osv"]},{"ecosystem":"Ubuntu:Pro:20.04:LTS","package":"pyjwt","fixed_in":["1.7.1-2ubuntu2.1+esm4"],"sources":["osv"]},{"ecosystem":"Ubuntu:22.04:LTS","package":"pyjwt","fixed_in":["2.3.0-1ubuntu0.6"],"sources":["osv"]},{"ecosystem":"Ubuntu:24.04:LTS","package":"pyjwt","fixed_in":["2.7.0-1ubuntu0.4"],"sources":["osv"]},{"ecosystem":"Ubuntu:26.10","package":"pyjwt","fixed_in":["2.13.0-1ubuntu1.1"],"sources":["osv"]},{"ecosystem":"Ubuntu:26.04:LTS","package":"pyjwt","fixed_in":["2.10.1-4ubuntu1.3"],"sources":["osv"]}],"affected":[{"source":"ghsa","ecosystem":"PyPI","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.0.0a1"},{"last_affected":"2.14.0"},{"fixed":"2.15.0"}]}]},{"source":"osv","ecosystem":"Azure Linux:3","package":"python-jwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.15.1-1"}]}]},{"source":"osv","ecosystem":"Alpaquita:25","package":"py3-jwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.10.1-r0"},{"fixed":"2.15.1-r0"}]}]},{"source":"osv","ecosystem":"Alpaquita:stream","package":"py3-jwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.8.0-r1"},{"fixed":"2.15.1-r0"}]}]},{"source":"osv","ecosystem":"TuxCare:PyPI","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.3.0"},{"fixed":"2.3.0.post4+tuxcare"}]}],"versions":["2.3.0","2.3.0.post1+tuxcare","2.3.0.post2+tuxcare","2.3.0.post3+tuxcare"],"bundled":7},{"source":"osv","ecosystem":"TuxCare:PyPI","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.10.1"},{"fixed":"2.10.1.post6+tuxcare"}]}],"versions":["2.10.1","2.10.1.post1+tuxcare","2.10.1.post2+tuxcare","2.10.1.post3+tuxcare","2.10.1.post4+tuxcare","2.10.1.post5+tuxcare"],"bundled":2},{"source":"osv","ecosystem":"TuxCare:PyPI","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.8.0"},{"fixed":"2.8.0.post5+tuxcare"}]}],"versions":["2.8.0","2.8.0.post1+tuxcare","2.8.0.post2+tuxcare","2.8.0.post3+tuxcare","2.8.0.post4+tuxcare"],"bundled":2},{"source":"osv","ecosystem":"Debian:12","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.10.1-1","2.10.1-2","2.10.1-3","2.10.1-4","2.11.0-2","2.12.1-1","2.13.0-1","2.14.0-1","2.15.0-1","2.15.1-1","2.6.0-1","2.6.0-1+deb12u1","2.7.0-1"]},{"source":"osv","ecosystem":"Debian:13","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.10.1-2","2.10.1-2+deb13u1","2.10.1-3","2.10.1-4","2.11.0-2","2.12.1-1","2.13.0-1","2.14.0-1","2.15.0-1","2.15.1-1"]},{"source":"osv","ecosystem":"Debian:14","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.15.0-1"}]}],"versions":["2.10.1-2","2.10.1-3","2.10.1-4","2.11.0-2","2.12.1-1","2.13.0-1","2.14.0-1"]},{"source":"osv","ecosystem":"PyPI","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.0.0a1"},{"fixed":"2.15.0"}]}],"versions":["2.0.0","2.0.0a1","2.0.0a2","2.0.1","2.1.0","2.10.0","2.10.1","2.11.0","2.12.0","2.12.1","2.13.0","2.14.0","2.2.0","2.3.0","2.4.0","2.5.0","2.6.0","2.7.0","2.8.0","2.9.0"]},{"source":"osv","ecosystem":"openEuler:24.03-LTS-SP4","package":"python-jwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-11.oe2403sp4"}]}],"bundled":5},{"source":"osv","ecosystem":"openEuler:22.03-LTS-SP4","package":"python-jwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.3.0-12.oe2203sp4"}]}],"bundled":4},{"source":"osv","ecosystem":"openEuler:24.03-LTS-SP1","package":"python-jwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-11.oe2403sp1"}]}],"bundled":5},{"source":"osv","ecosystem":"openEuler:24.03-LTS-SP3","package":"python-jwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-11.oe2403sp3"}]}],"bundled":5},{"source":"osv","ecosystem":"PyPI","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.0.0a1"},{"fixed":"2.15.0"}]}],"versions":["2.0.0","2.0.0a1","2.0.0a2","2.0.1","2.1.0","2.10.0","2.10.1","2.11.0","2.12.0","2.12.1","2.13.0","2.14.0","2.2.0","2.3.0","2.4.0","2.5.0","2.6.0","2.7.0","2.8.0","2.9.0"]},{"source":"osv","ecosystem":"SUSE:Linux Micro 6.2","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.12.1-160000.3.1"}]}],"bundled":10},{"source":"osv","ecosystem":"SUSE:Linux Micro 6.0","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.9.0-159998.1.1"}]}],"bundled":9},{"source":"osv","ecosystem":"SUSE:Linux Enterprise Server 16.0","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.12.1-160000.3.1"}]}],"bundled":10},{"source":"osv","ecosystem":"SUSE:Linux Enterprise Server for SAP applications 16.0","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.12.1-160000.3.1"}]}],"bundled":10},{"source":"osv","ecosystem":"SUSE:Linux Micro 6.1","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.12.1-slfo.1.1_3.1"}]}],"bundled":10},{"source":"osv","ecosystem":"SUSE:Linux Enterprise Module for Public Cloud 15 SP4","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-150400.8.20.1"}]}],"bundled":8},{"source":"osv","ecosystem":"SUSE:Linux Enterprise Module for Python 3 15 SP7","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-150400.8.20.1"}]}],"bundled":8},{"source":"osv","ecosystem":"SUSE:Linux Enterprise High Performance Computing 15 SP4-ESPOS","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-150400.8.20.1"}]}],"bundled":8},{"source":"osv","ecosystem":"SUSE:Linux Enterprise High Performance Computing 15 SP4-LTSS","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-150400.8.20.1"}]}],"bundled":8},{"source":"osv","ecosystem":"SUSE:Linux Enterprise High Performance Computing 15 SP5-ESPOS","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-150400.8.20.1"}]}],"bundled":8},{"source":"osv","ecosystem":"SUSE:Linux Enterprise High Performance Computing 15 SP5-LTSS","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-150400.8.20.1"}]}],"bundled":8},{"source":"osv","ecosystem":"SUSE:Linux Enterprise Server 15 SP4-LTSS","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-150400.8.20.1"}]}],"bundled":8},{"source":"osv","ecosystem":"SUSE:Linux Enterprise Server 15 SP5-LTSS","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-150400.8.20.1"}]}],"bundled":8},{"source":"osv","ecosystem":"SUSE:Linux Enterprise Server 15 SP6-LTSS","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-150400.8.20.1"}]}],"bundled":8},{"source":"osv","ecosystem":"SUSE:Linux Enterprise Server for SAP Applications 15 SP4","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-150400.8.20.1"}]}],"bundled":8},{"source":"osv","ecosystem":"SUSE:Linux Enterprise Server for SAP Applications 15 SP5","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-150400.8.20.1"}]}],"bundled":8},{"source":"osv","ecosystem":"SUSE:Linux Enterprise Server for SAP Applications 15 SP6","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-150400.8.20.1"}]}],"bundled":8},{"source":"osv","ecosystem":"Ubuntu:Pro:16.04:LTS","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.3.0-1ubuntu0.1+esm4"}]}],"versions":["1.0.0-0ubuntu1","1.3.0-1","1.3.0-1ubuntu0.1","1.3.0-1ubuntu0.1+esm1","1.3.0-1ubuntu0.1+esm2","1.3.0-1ubuntu0.1+esm3"]},{"source":"osv","ecosystem":"Ubuntu:Pro:18.04:LTS","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.5.3+ds1-1ubuntu0.1+esm4"}]}],"versions":["1.4.2-1.1","1.5.3+ds1-1","1.5.3+ds1-1ubuntu0.1","1.5.3+ds1-1ubuntu0.1+esm1","1.5.3+ds1-1ubuntu0.1+esm2","1.5.3+ds1-1ubuntu0.1+esm3"]},{"source":"osv","ecosystem":"Ubuntu:Pro:20.04:LTS","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.7.1-2ubuntu2.1+esm4"}]}],"versions":["1.7.0-2","1.7.1-1","1.7.1-2ubuntu1","1.7.1-2ubuntu2","1.7.1-2ubuntu2.1","1.7.1-2ubuntu2.1+esm1","1.7.1-2ubuntu2.1+esm2","1.7.1-2ubuntu2.1+esm3"]},{"source":"osv","ecosystem":"Ubuntu:22.04:LTS","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.3.0-1ubuntu0.6"}]}],"versions":["1.7.1-2ubuntu2","2.1.0-1","2.3.0-1","2.3.0-1ubuntu0.1","2.3.0-1ubuntu0.2","2.3.0-1ubuntu0.3","2.3.0-1ubuntu0.4","2.3.0-1ubuntu0.5"]},{"source":"osv","ecosystem":"Ubuntu:24.04:LTS","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.7.0-1ubuntu0.4"}]}],"versions":["2.7.0-1","2.7.0-1ubuntu0.1","2.7.0-1ubuntu0.2","2.7.0-1ubuntu0.3"]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.13.0-1ubuntu1.1"}]}],"versions":["2.10.1-4ubuntu1","2.12.1-1","2.13.0-1","2.13.0-1ubuntu1"]},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.10.1-4ubuntu1.3"}]}],"versions":["2.10.1-2","2.10.1-3","2.10.1-3build1","2.10.1-4","2.10.1-4ubuntu1","2.10.1-4ubuntu1.1","2.10.1-4ubuntu1.2"]},{"source":"osv","ecosystem":"Ubuntu:Pro:16.04:LTS","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.3.0-1ubuntu0.1+esm4"}]}],"versions":["1.0.0-0ubuntu1","1.3.0-1","1.3.0-1ubuntu0.1","1.3.0-1ubuntu0.1+esm1","1.3.0-1ubuntu0.1+esm2","1.3.0-1ubuntu0.1+esm3"],"bundled":4},{"source":"osv","ecosystem":"Ubuntu:Pro:18.04:LTS","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.5.3+ds1-1ubuntu0.1+esm4"}]}],"versions":["1.4.2-1.1","1.5.3+ds1-1","1.5.3+ds1-1ubuntu0.1","1.5.3+ds1-1ubuntu0.1+esm1","1.5.3+ds1-1ubuntu0.1+esm2","1.5.3+ds1-1ubuntu0.1+esm3"],"bundled":4},{"source":"osv","ecosystem":"Ubuntu:Pro:20.04:LTS","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.7.1-2ubuntu2.1+esm4"}]}],"versions":["1.7.0-2","1.7.1-1","1.7.1-2ubuntu1","1.7.1-2ubuntu2","1.7.1-2ubuntu2.1","1.7.1-2ubuntu2.1+esm1","1.7.1-2ubuntu2.1+esm2","1.7.1-2ubuntu2.1+esm3"],"bundled":4},{"source":"osv","ecosystem":"Ubuntu:22.04:LTS","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.3.0-1ubuntu0.6"}]}],"versions":["1.7.1-2ubuntu2","2.1.0-1","2.3.0-1","2.3.0-1ubuntu0.1","2.3.0-1ubuntu0.2","2.3.0-1ubuntu0.3","2.3.0-1ubuntu0.4","2.3.0-1ubuntu0.5"],"bundled":4},{"source":"osv","ecosystem":"Ubuntu:24.04:LTS","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.7.0-1ubuntu0.4"}]}],"versions":["2.7.0-1","2.7.0-1ubuntu0.1","2.7.0-1ubuntu0.2","2.7.0-1ubuntu0.3"],"bundled":4},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.13.0-1ubuntu1.1"}]}],"versions":["2.10.1-4ubuntu1","2.12.1-1","2.13.0-1","2.13.0-1ubuntu1"],"bundled":4},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"pyjwt","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.10.1-4ubuntu1.3"}]}],"versions":["2.10.1-2","2.10.1-3","2.10.1-3build1","2.10.1-4","2.10.1-4ubuntu1","2.10.1-4ubuntu1.1","2.10.1-4ubuntu1.2"],"bundled":4},{"source":"osv","ecosystem":"openSUSE:Tumbleweed","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.15.1-1.1"}]}],"bundled":9},{"source":"osv","ecosystem":"openSUSE:Leap 16.0","package":"python-PyJWT","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.12.1-160000.3.1"}]}],"bundled":10}],"products":[{"vendor":"jpadilla","product":"pyjwt"},{"vendor":"pyjwt_project","product":"pyjwt"}],"references":[{"url":"https://github.com/jpadilla/pyjwt/security/advisories/GHSA-42vr-xj54-vc7v","tags":["x_refsource_CONFIRM","Exploit","Mitigation","Vendor Advisory","advisory","web","report"]},{"url":"https://github.com/jpadilla/pyjwt/commit/5fde08a6cf906aa7698de2d6391d88b73006b17b","tags":["x_refsource_MISC","Patch","fix","web","report"]},{"url":"https://github.com/jpadilla/pyjwt/releases/tag/2.15.0","tags":["x_refsource_MISC","Product","Release Notes","web","report"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-101918","tags":["web","advisory"]},{"url":"https://github.com/advisories/GHSA-42vr-xj54-vc7v","tags":["advisory"]},{"url":"https://docs.bell-sw.com/security/cves/CVE-2026-101918","tags":["advisory"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/101xxx/CVE-2026-101918.json","tags":["advisory"]},{"url":"https://security-tracker.debian.org/tracker/CVE-2026-101918","tags":["advisory"]},{"url":"https://github.com/jpadilla/pyjwt","tags":["package"]},{"url":"https://www.openeuler.org/zh/security/security-bulletins/detail/?id=openEuler-SA-2026-4453","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-101917","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-102265","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-102269","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-102275","tags":["advisory"]},{"url":"https://www.openeuler.org/zh/security/security-bulletins/detail/?id=openEuler-SA-2026-4454","tags":["advisory"]},{"url":"https://www.openeuler.org/zh/security/security-bulletins/detail/?id=openEuler-SA-2026-4455","tags":["advisory"]},{"url":"https://www.openeuler.org/zh/security/security-bulletins/detail/?id=openEuler-SA-2026-4456","tags":["advisory"]},{"url":"https://pypi.org/project/pyjwt","tags":["package"]},{"url":"https://www.suse.com/support/update/announcement/2026/suse-su-202624126-1/","tags":["advisory"]},{"url":"https://bugzilla.suse.com/1283060","tags":["report"]},{"url":"https://bugzilla.suse.com/1283061","tags":["report"]},{"url":"https://bugzilla.suse.com/1283064","tags":["report"]},{"url":"https://bugzilla.suse.com/1283065","tags":["report"]},{"url":"https://bugzilla.suse.com/1283066","tags":["report"]},{"url":"https://bugzilla.suse.com/1283067","tags":["report"]},{"url":"https://bugzilla.suse.com/1283068","tags":["report"]},{"url":"https://bugzilla.suse.com/1283071","tags":["report"]},{"url":"https://bugzilla.suse.com/1283072","tags":["report"]},{"url":"https://bugzilla.suse.com/1283829","tags":["report"]},{"url":"https://www.suse.com/security/cve/CVE-2026-101917","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-101918","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-102267","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-102268","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-102269","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-102270","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-102271","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-102274","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-102275","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-103001","tags":["web"]},{"url":"https://www.suse.com/support/update/announcement/2026/suse-su-202624134-1/","tags":["advisory"]},{"url":"https://www.suse.com/support/update/announcement/2026/suse-su-202624219-1/","tags":["advisory"]},{"url":"https://www.suse.com/support/update/announcement/2026/suse-su-202624377-1/","tags":["advisory"]},{"url":"https://www.suse.com/support/update/announcement/2026/suse-su-20265064-1/","tags":["advisory"]},{"url":"https://ubuntu.com/security/CVE-2026-101918","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-101918","tags":["report"]},{"url":"https://ubuntu.com/security/notices/USN-8934-1","tags":["advisory"]},{"url":"https://ubuntu.com/security/CVE-2026-101917","tags":["report"]},{"url":"https://ubuntu.com/security/CVE-2026-102274","tags":["report"]},{"url":"https://ubuntu.com/security/CVE-2026-102275","tags":["report"]},{"url":"","tags":["advisory"]},{"url":"https://www.suse.com/security/cve/CVE-2026-102266","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-102272","tags":["web"]}],"sources":{"cve":[{"id":"CVE-2026-101918","title":"PyJWT: Unauthenticated RecursionError DoS in pre-verification payload parse (PyJWKClient.get_signing_key_from_jwt / verify_signature=False)","description":"PyJWT is a Python implementation of JSON Web Token standards. From 2.0.0a1 until 2.15.0, PyJWT PyJWKClient.get_signing_key_from_jwt is affected because payload parser catches ValueError but not RecursionError. This occurs when an attacker-controlled recursively nested payload reaches json.loads. As a result, documented PyJWT exception handling does not contain the failure. Consequently, an unauthenticated request can raise an exception that may produce an HTTP 500 response. The advisory-defined affected implementation also includes jwt/api_jwt.py, verify_signature=False. This issue is fixed in version 2.15.0.","status":"published","published":"2026-09-28T20:11:55.278Z","modified":"2026-09-29T13:57:29.516Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L","level":"medium","assessor":"cna"}],"cwes":["CWE-248"],"updated_at":"2026-11-02T14:20:10.143031Z"}],"euvd":[{"id":"EUVD-2026-88479","description":"PyJWT is a Python implementation of JSON Web Token standards. From 2.0.0a1 until 2.15.0, PyJWT PyJWKClient.get_signing_key_from_jwt is affected because payload parser catches ValueError but not RecursionError. This occurs when an attacker-controlled recursively nested payload reaches json.loads. As a result, documented PyJWT exception handling does not contain the failure. Consequently, an unauthenticated request can raise an exception that may produce an HTTP 500 response. The advisory-defined affected implementation also includes jwt/api_jwt.py, verify_signature=False. This issue is fixed in version 2.15.0.","status":"published","published":"2026-09-28T20:11:55Z","modified":"2026-09-29T13:57:29Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L","level":"medium"}],"updated_at":"2026-11-02T17:27:52.331616Z"}],"ghsa":[{"id":"GHSA-42vr-xj54-vc7v","title":"PyJWT: Unauthenticated RecursionError DoS in pre-verification payload parse (PyJWKClient.get_signing_key_from_jwt / verify_signature=False)","description":"## Summary\n\n`PyJWKClient.get_signing_key_from_jwt(token)` — the first step of the JWKS\nverification flow documented in `docs/usage.rst` — must decode a token's\npayload before its signature can be checked, via\n`jwt.api_jwt.decode_complete(token, options={\"verify_signature\": False})`.\nThat call parses the payload with `json.loads` in `PyJWT._decode_payload`\n(`jwt/api_jwt.py:297-300`), whose `except` clause catches only `ValueError`.\nA payload that is valid JSON but nested ~20,000 levels deep makes\n`json.loads` raise `RecursionError`, which is **not** a `ValueError` and\nescapes as a raw, undocumented exception type — not `DecodeError`,\n`InvalidTokenError`, or `PyJWTError`, so every documented error-handling\npattern in `docs/usage.rst` misses it.\n\nThe token needs no valid signature and no network access — the crash\nhappens during payload parsing, before the `kid` is even looked up. A\nsingle unauthenticated ~50KB request crashes the caller's auth handler\n(HTTP 500 / dead worker), repeatably. The same path is reachable through\nplain `jwt.decode(token, options={\"verify_signature\": False})` too.\n\nNotably, this project already fixed the **identical** bug class for the\nJWS **header** path — `PyJWS._load` catches `(ValueError, RecursionError)`\nand wraps it in `DecodeError` (`jwt/api_jws.py:360-361`), and\n`CHANGELOG.rst` (v2.14.0, \"Security\") states \"Handle deeply nested and\nmalformed JWS/JWK input without uncaught recursion errors.\" The payload\npath — the one part of a forged token an unauthenticated attacker fully\ncontrols — was left catching `ValueError` alone, so that security fix does\nnot fully hold.\n\nA second, related instance: `PyJWKClient.fetch_data` (`jwt/jwks_client.py:168`)\nparses a JWKS endpoint's response with `json.load(response)` inside a\n`try` that only catches `(URLError, TimeoutError, http.client.HTTPException)`\n— a deeply-nested JSON response from a JWKS endpoint raises the same raw\n`RecursionError`, uncaught entirely (worse than the payload path, which at\nleast caught plain `ValueError`).\n\n**Affected versions:** confirmed present in the current release, 2.14.0,\nand on the current `master` branch (commit `4adcd02722f5011c60079d3978dfc167b9a8eaa5`).\n\n## Reproduction\n\n```python\nimport base64, json, jwt\n\ndef b64url(b):\n    return base64.urlsafe_b64encode(b).rstrip(b\"=\")\n\nheader = b64url(json.dumps({\"alg\": \"HS256\", \"typ\": \"JWT\"}).encode())\npayload = b64url(b\"[\" * 20_000 + b\"]\" * 20_000)\ntoken = (header + b\".\" + payload + b\".\" + b64url(b\"forged-sig\")).decode()\n\njwt.decode(token, options={\"verify_signature\": False})\n# raises: RecursionError (not DecodeError/InvalidTokenError/PyJWTError)\n```\n\nControl: the same deeply-nested structure moved into the token's **header**\ninstead of its payload is correctly converted to `jwt.DecodeError` by the\nalready-hardened `jwt/api_jws.py:360` — confirming the payload path is\nspecifically the missed half of the v2.14.0 hardening, not a general gap.\n\n## Impact assessment\n\nUnauthenticated denial-of-service via unhandled exception on an auth path.\nNot an auth bypass — rated medium. With signature verification enabled,\nthis parse runs after `_verify_signature`, so only the pre-verification\npaths (`get_signing_key_from_jwt`, explicit `verify_signature=False`) are\nattacker-reachable pre-auth; the JWKS-endpoint variant requires control of\n(or a MITM on) the configured JWKS endpoint rather than being reachable\nfrom an arbitrary client token.\n\n## Suggested fix\n\nIn `jwt/api_jwt.py:299`, change `except ValueError as e:` to\n`except (ValueError, RecursionError) as e:`, mirroring\n`jwt/api_jws.py:360` exactly. In `jwt/jwks_client.py`, add the same\n`(ValueError, RecursionError)` handling around `json.load(response)` in\n`fetch_data`, raising `PyJWKClientError` (consistent with the method's\nexisting documented error contract). A patch implementing both, verified\nagainst the full test suite (457 passed, 4 skipped — pre-existing,\nenvironment-related) and against the reproduction above (now correctly\nraises `DecodeError`), is attached (`fix.patch`).\n\n## Discovery method\n\nFound and verified using `scopegrep` (https://github.com/not-ekalabya/scopegrep)\n— a semantic code-retrieval tool that surfaces every other call site of a\nsymbol alongside relevance-ranked results, which is what surfaced the\nalready-hardened header path as the direct comparison here — paired with\nan LLM coding agent (GLM-5.3) run as an open-ended security review of this\nrepository. Independently reproduced against the exact commit above before\nthis report was written. Happy to share the full session transcript on\nrequest.\n\n## Disclosure status\n\nNot shared with any other party or published. Submitting through this\nprivate channel per the project's stated security policy; no planned\npublic/conference disclosure ahead of a coordinated timeline.\n\n\n---\n\n## Maintainer triage update (2026-09-22)\n\n### Confirmed finding and scope\n\nWe confirmed that an attacker-controlled recursively nested JWT payload can cause a raw Python `RecursionError` to escape PyJWT at PyJWT 2.14.0 and the tested current source. The confirmed in-scope paths are direct decoding with `verify_signature=False` and `PyJWKClient.get_signing_key_from_jwt`, where payload parsing occurs before key lookup.\n\nThe demonstrated impact is limited to an uncaught exception for the affected call, which may surface as an application HTTP 500 when the application does not catch it. Testing did not demonstrate a worker or process crash, persistent resource exhaustion, resource amplification, authentication bypass, or confidentiality or integrity impact.\n\nThe separate JWKS-response subclaim is out of scope under the policy boundary that requires the application to trust its configured JWKS source and transport. The confirmed payload finding is not a duplicate of the earlier protected-header parser finding: it occurs in a distinct payload parsing path that remained affected after the earlier header-only fix.\n\n### Version and remediation status\n\nHistorical testing reproduced the confirmed payload behavior in all 20 official supported PyJWT 2.x releases from 2.0.0a1 through 2.14.0, inclusive. Unsupported PyJWT 1.7.1 also reproduces the behavior, but it is excluded from the advisory range under the supported-2.x policy. No supported unaffected release and no patched release exists. The exact evidence is `/Users/jpadilla/.codex/security-advisories/pyjwt/GHSA-42vr-xj54-vc7v-historical-range-20260922.md` (SHA-256 `c48f1ac35641e9382d53e6a879a71ad9a8fb4432bbe871f2b8330f8d166a2d81`) and `/Users/jpadilla/.codex/security-advisories/pyjwt/historical-range-42vr-20260922/historical-range-results.json` (SHA-256 `324997f231561bf6da39b8f9d1e272f69bfde8871a7863f5cb7b70e22e91f076`). The evidence-backed supported affected range is `\u003e= 2.0.0a1, \u003c= 2.14.0`.\n\nHistorical range verification is complete. A local fix commit exists and has passed independent review and the complete local CI suite, but it has not been merged into `master` or released. Consequently, `patched_versions` remains empty and this advisory remains in `triage`. The remaining next step is a maintainer decision on remediation and merge. After a fix lands in `master` and is released, `patched_versions` and advisory lifecycle can be updated in a separate approved batch.\n\n---\n\n## Maintainer remediation update (2026-09-23)\n\nThe confirmed payload-parser finding has been fixed on `master`. Commit\n`5fde08a6cf906aa7698de2d6391d88b73006b17b` converts a recursive\npayload parse failure to the expected `DecodeError`; commit\n`9bc06658f875b9b40091539140bbbdc4639161c3` makes the regression tests\ndeterministic across supported Python versions. This update supersedes the\n2026-09-22 remediation-status statement that the fix had not landed.\n\nThe original pre-verification payload reproducer and the\n`PyJWKClient.get_signing_key_from_jwt` path were covered by regression tests.\nThe exact landed tree passed the full 39-environment local tox matrix and\nGitHub CI for commit `9bc06658f875b9b40091539140bbbdc4639161c3` passed\nall 25 jobs, including Ubuntu Python 3.14 and 3.15. The demonstrated impact\nremains an uncaught request-level exception in affected releases; there is\nstill no evidence of process termination, persistent resource exhaustion,\nauthentication bypass, or confidentiality or integrity impact.\n\nThe supported affected range remains `\u003e= 2.0.0a1, \u003c= 2.14.0`. The latest\nreleased version is 2.14.0, which predates these commits; no released\npatched version exists yet, so `patched_versions` remains unset. CVSS v3.1\n5.3 (Medium) and CWE-248 remain unchanged. The advisory may now move from\ntriage to private draft. The next lifecycle step is a new supported 2.x\nrelease containing the fix, followed by separately approved patched-version\nand publication updates after release verification.\n\n---\n\n## Maintainer release update (2026-09-23)\n\nPyJWT 2.15.0 is the first released version containing the payload-parser fix. Its GitHub release tag points to commit `1d41a6478e1562e68ff667fcd703356acf085f68`, which includes fix commit `5fde08a6cf906aa7698de2d6391d88b73006b17b` and deterministic regression-test commit `9bc06658f875b9b40091539140bbbdc4639161c3`. PyPI published both the wheel and source distribution from that release commit through the successful production workflow at https://github.com/jpadilla/pyjwt/actions/runs/35891602963.\n\nThe published PyPI wheel (`pyjwt-2.15.0-py3-none-any.whl`, SHA-256 `7a3742debf6b879e912dbb9819ceec1594be812452b78c5f2e2dfc56564954f8`) was checked directly: the deeply nested unsigned payload now raises `DecodeError`, while an ordinary unsigned payload still decodes. The supported affected range remains `\u003e= 2.0.0a1, \u003c= 2.14.0`; the patched version is `2.15.0`. Earlier statements in this advisory that no released patched version exists are superseded by this update.\n\nThe confirmed impact remains an uncaught request-level exception in affected versions, not a demonstrated process crash or authentication bypass. The separate JWKS-response subclaim remains outside this advisory's confirmed PyJWT-owned scope.","status":"published","published":"2026-09-30T15:41:05Z","modified":"2026-09-30T15:41:07Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L","level":"medium"}],"cwes":["CWE-248"],"updated_at":"2026-11-02T14:41:23.783773Z"}],"nvd":[{"id":"CVE-2026-101918","description":"PyJWT is a Python implementation of JSON Web Token standards. From 2.0.0a1 until 2.15.0, PyJWT PyJWKClient.get_signing_key_from_jwt is affected because payload parser catches ValueError but not RecursionError. This occurs when an attacker-controlled recursively nested payload reaches json.loads. As a result, documented PyJWT exception handling does not contain the failure. Consequently, an unauthenticated request can raise an exception that may produce an HTTP 500 response. The advisory-defined affected implementation also includes jwt/api_jwt.py, verify_signature=False. This issue is fixed in version 2.15.0.","status":"published","published":"2026-09-28T21:17:13.41Z","modified":"2026-10-07T20:59:17.86Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L","level":"medium","assessor":"secondary"},{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"primary"}],"cwes":["CWE-248"],"updated_at":"2026-11-02T14:12:52.413234Z"}],"osv":[{"id":"BELL-CVE-2026-101918","status":"published","published":"2026-10-01T06:08:32.662695Z","modified":"2026-11-07T07:15:04.201216773Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-07T07:40:27.39378Z"},{"id":"CVE-2026-101918","title":"PyJWT: Unauthenticated RecursionError DoS in pre-verification payload parse (PyJWKClient.get_signing_key_from_jwt / verify_signature=False)","description":"PyJWT is a Python implementation of JSON Web Token standards. From 2.0.0a1 until 2.15.0, PyJWT PyJWKClient.get_signing_key_from_jwt is affected because payload parser catches ValueError but not RecursionError. This occurs when an attacker-controlled recursively nested payload reaches json.loads. As a result, documented PyJWT exception handling does not contain the failure. Consequently, an unauthenticated request can raise an exception that may produce an HTTP 500 response. The advisory-defined affected implementation also includes jwt/api_jwt.py, verify_signature=False. This issue is fixed in version 2.15.0.","status":"published","published":"2026-09-28T20:11:55.278Z","modified":"2026-11-03T22:56:57.818386964Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L","level":"medium"}],"cwes":["CWE-248"],"updated_at":"2026-11-03T23:33:36.422322Z"},{"id":"DEBIAN-CVE-2026-101918","description":"PyJWT is a Python implementation of JSON Web Token standards. From 2.0.0a1 until 2.15.0, PyJWT PyJWKClient.get_signing_key_from_jwt is affected because payload parser catches ValueError but not RecursionError. This occurs when an attacker-controlled recursively nested payload reaches json.loads. As a result, documented PyJWT exception handling does not contain the failure. Consequently, an unauthenticated request can raise an exception that may produce an HTTP 500 response. The advisory-defined affected implementation also includes jwt/api_jwt.py, verify_signature=False. This issue is fixed in version 2.15.0.","status":"published","published":"2026-09-28T21:17:13.41Z","modified":"2026-10-08T10:00:27.754035377Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T15:45:48.440897Z"},{"id":"GHSA-42vr-xj54-vc7v","title":"PyJWT: Unauthenticated RecursionError DoS in pre-verification payload parse (PyJWKClient.get_signing_key_from_jwt / verify_signature=False)","description":"## Summary\n\n`PyJWKClient.get_signing_key_from_jwt(token)` — the first step of the JWKS\nverification flow documented in `docs/usage.rst` — must decode a token's\npayload before its signature can be checked, via\n`jwt.api_jwt.decode_complete(token, options={\"verify_signature\": False})`.\nThat call parses the payload with `json.loads` in `PyJWT._decode_payload`\n(`jwt/api_jwt.py:297-300`), whose `except` clause catches only `ValueError`.\nA payload that is valid JSON but nested ~20,000 levels deep makes\n`json.loads` raise `RecursionError`, which is **not** a `ValueError` and\nescapes as a raw, undocumented exception type — not `DecodeError`,\n`InvalidTokenError`, or `PyJWTError`, so every documented error-handling\npattern in `docs/usage.rst` misses it.\n\nThe token needs no valid signature and no network access — the crash\nhappens during payload parsing, before the `kid` is even looked up. A\nsingle unauthenticated ~50KB request crashes the caller's auth handler\n(HTTP 500 / dead worker), repeatably. The same path is reachable through\nplain `jwt.decode(token, options={\"verify_signature\": False})` too.\n\nNotably, this project already fixed the **identical** bug class for the\nJWS **header** path — `PyJWS._load` catches `(ValueError, RecursionError)`\nand wraps it in `DecodeError` (`jwt/api_jws.py:360-361`), and\n`CHANGELOG.rst` (v2.14.0, \"Security\") states \"Handle deeply nested and\nmalformed JWS/JWK input without uncaught recursion errors.\" The payload\npath — the one part of a forged token an unauthenticated attacker fully\ncontrols — was left catching `ValueError` alone, so that security fix does\nnot fully hold.\n\nA second, related instance: `PyJWKClient.fetch_data` (`jwt/jwks_client.py:168`)\nparses a JWKS endpoint's response with `json.load(response)` inside a\n`try` that only catches `(URLError, TimeoutError, http.client.HTTPException)`\n— a deeply-nested JSON response from a JWKS endpoint raises the same raw\n`RecursionError`, uncaught entirely (worse than the payload path, which at\nleast caught plain `ValueError`).\n\n**Affected versions:** confirmed present in the current release, 2.14.0,\nand on the current `master` branch (commit `4adcd02722f5011c60079d3978dfc167b9a8eaa5`).\n\n## Reproduction\n\n```python\nimport base64, json, jwt\n\ndef b64url(b):\n    return base64.urlsafe_b64encode(b).rstrip(b\"=\")\n\nheader = b64url(json.dumps({\"alg\": \"HS256\", \"typ\": \"JWT\"}).encode())\npayload = b64url(b\"[\" * 20_000 + b\"]\" * 20_000)\ntoken = (header + b\".\" + payload + b\".\" + b64url(b\"forged-sig\")).decode()\n\njwt.decode(token, options={\"verify_signature\": False})\n# raises: RecursionError (not DecodeError/InvalidTokenError/PyJWTError)\n```\n\nControl: the same deeply-nested structure moved into the token's **header**\ninstead of its payload is correctly converted to `jwt.DecodeError` by the\nalready-hardened `jwt/api_jws.py:360` — confirming the payload path is\nspecifically the missed half of the v2.14.0 hardening, not a general gap.\n\n## Impact assessment\n\nUnauthenticated denial-of-service via unhandled exception on an auth path.\nNot an auth bypass — rated medium. With signature verification enabled,\nthis parse runs after `_verify_signature`, so only the pre-verification\npaths (`get_signing_key_from_jwt`, explicit `verify_signature=False`) are\nattacker-reachable pre-auth; the JWKS-endpoint variant requires control of\n(or a MITM on) the configured JWKS endpoint rather than being reachable\nfrom an arbitrary client token.\n\n## Suggested fix\n\nIn `jwt/api_jwt.py:299`, change `except ValueError as e:` to\n`except (ValueError, RecursionError) as e:`, mirroring\n`jwt/api_jws.py:360` exactly. In `jwt/jwks_client.py`, add the same\n`(ValueError, RecursionError)` handling around `json.load(response)` in\n`fetch_data`, raising `PyJWKClientError` (consistent with the method's\nexisting documented error contract). A patch implementing both, verified\nagainst the full test suite (457 passed, 4 skipped — pre-existing,\nenvironment-related) and against the reproduction above (now correctly\nraises `DecodeError`), is attached (`fix.patch`).\n\n## Discovery method\n\nFound and verified using `scopegrep` (https://github.com/not-ekalabya/scopegrep)\n— a semantic code-retrieval tool that surfaces every other call site of a\nsymbol alongside relevance-ranked results, which is what surfaced the\nalready-hardened header path as the direct comparison here — paired with\nan LLM coding agent (GLM-5.3) run as an open-ended security review of this\nrepository. Independently reproduced against the exact commit above before\nthis report was written. Happy to share the full session transcript on\nrequest.\n\n## Disclosure status\n\nNot shared with any other party or published. Submitting through this\nprivate channel per the project's stated security policy; no planned\npublic/conference disclosure ahead of a coordinated timeline.\n\n\n---\n\n## Maintainer triage update (2026-09-22)\n\n### Confirmed finding and scope\n\nWe confirmed that an attacker-controlled recursively nested JWT payload can cause a raw Python `RecursionError` to escape PyJWT at PyJWT 2.14.0 and the tested current source. The confirmed in-scope paths are direct decoding with `verify_signature=False` and `PyJWKClient.get_signing_key_from_jwt`, where payload parsing occurs before key lookup.\n\nThe demonstrated impact is limited to an uncaught exception for the affected call, which may surface as an application HTTP 500 when the application does not catch it. Testing did not demonstrate a worker or process crash, persistent resource exhaustion, resource amplification, authentication bypass, or confidentiality or integrity impact.\n\nThe separate JWKS-response subclaim is out of scope under the policy boundary that requires the application to trust its configured JWKS source and transport. The confirmed payload finding is not a duplicate of the earlier protected-header parser finding: it occurs in a distinct payload parsing path that remained affected after the earlier header-only fix.\n\n### Version and remediation status\n\nHistorical testing reproduced the confirmed payload behavior in all 20 official supported PyJWT 2.x releases from 2.0.0a1 through 2.14.0, inclusive. Unsupported PyJWT 1.7.1 also reproduces the behavior, but it is excluded from the advisory range under the supported-2.x policy. No supported unaffected release and no patched release exists. The exact evidence is `/Users/jpadilla/.codex/security-advisories/pyjwt/GHSA-42vr-xj54-vc7v-historical-range-20260922.md` (SHA-256 `c48f1ac35641e9382d53e6a879a71ad9a8fb4432bbe871f2b8330f8d166a2d81`) and `/Users/jpadilla/.codex/security-advisories/pyjwt/historical-range-42vr-20260922/historical-range-results.json` (SHA-256 `324997f231561bf6da39b8f9d1e272f69bfde8871a7863f5cb7b70e22e91f076`). The evidence-backed supported affected range is `\u003e= 2.0.0a1, \u003c= 2.14.0`.\n\nHistorical range verification is complete. A local fix commit exists and has passed independent review and the complete local CI suite, but it has not been merged into `master` or released. Consequently, `patched_versions` remains empty and this advisory remains in `triage`. The remaining next step is a maintainer decision on remediation and merge. After a fix lands in `master` and is released, `patched_versions` and advisory lifecycle can be updated in a separate approved batch.\n\n---\n\n## Maintainer remediation update (2026-09-23)\n\nThe confirmed payload-parser finding has been fixed on `master`. Commit\n`5fde08a6cf906aa7698de2d6391d88b73006b17b` converts a recursive\npayload parse failure to the expected `DecodeError`; commit\n`9bc06658f875b9b40091539140bbbdc4639161c3` makes the regression tests\ndeterministic across supported Python versions. This update supersedes the\n2026-09-22 remediation-status statement that the fix had not landed.\n\nThe original pre-verification payload reproducer and the\n`PyJWKClient.get_signing_key_from_jwt` path were covered by regression tests.\nThe exact landed tree passed the full 39-environment local tox matrix and\nGitHub CI for commit `9bc06658f875b9b40091539140bbbdc4639161c3` passed\nall 25 jobs, including Ubuntu Python 3.14 and 3.15. The demonstrated impact\nremains an uncaught request-level exception in affected releases; there is\nstill no evidence of process termination, persistent resource exhaustion,\nauthentication bypass, or confidentiality or integrity impact.\n\nThe supported affected range remains `\u003e= 2.0.0a1, \u003c= 2.14.0`. The latest\nreleased version is 2.14.0, which predates these commits; no released\npatched version exists yet, so `patched_versions` remains unset. CVSS v3.1\n5.3 (Medium) and CWE-248 remain unchanged. The advisory may now move from\ntriage to private draft. The next lifecycle step is a new supported 2.x\nrelease containing the fix, followed by separately approved patched-version\nand publication updates after release verification.\n\n---\n\n## Maintainer release update (2026-09-23)\n\nPyJWT 2.15.0 is the first released version containing the payload-parser fix. Its GitHub release tag points to commit `1d41a6478e1562e68ff667fcd703356acf085f68`, which includes fix commit `5fde08a6cf906aa7698de2d6391d88b73006b17b` and deterministic regression-test commit `9bc06658f875b9b40091539140bbbdc4639161c3`. PyPI published both the wheel and source distribution from that release commit through the successful production workflow at https://github.com/jpadilla/pyjwt/actions/runs/35891602963.\n\nThe published PyPI wheel (`pyjwt-2.15.0-py3-none-any.whl`, SHA-256 `7a3742debf6b879e912dbb9819ceec1594be812452b78c5f2e2dfc56564954f8`) was checked directly: the deeply nested unsigned payload now raises `DecodeError`, while an ordinary unsigned payload still decodes. The supported affected range remains `\u003e= 2.0.0a1, \u003c= 2.14.0`; the patched version is `2.15.0`. Earlier statements in this advisory that no released patched version exists are superseded by this update.\n\nThe confirmed impact remains an uncaught request-level exception in affected versions, not a demonstrated process crash or authentication bypass. The separate JWKS-response subclaim remains outside this advisory's confirmed PyJWT-owned scope.","status":"published","published":"2026-09-30T15:41:05Z","modified":"2026-10-01T17:56:09.538835697Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L","level":"medium"}],"cwes":["CWE-248"],"updated_at":"2026-11-02T15:46:36.434231Z"},{"id":"OESA-2026-4453","title":"python-jwt security update","description":"setup.py test %endif\r\n\r\nSecurity Fix(es):\n\nPyJWT is a Python implementation of JSON Web Token standards. Prior to 2.14.0, PyJWT get_signing_key_from_jwt is affected because unknown kid misses force refreshes without a negative cache or minimum refresh interval. This occurs when unauthenticated tokens repeatedly use the same unknown kid or varying kid values absent from the cached JWKS. As a result, each cache miss causes PyJWKClient to refresh the JWKS. Consequently, attacker traffic can amplify outbound requests to the configured JWKS endpoint. This issue is fixed in version 2.14.0.(CVE-2026-101917)\n\nPyJWT is a Python implementation of JSON Web Token standards. From 2.0.0a1 until 2.15.0, PyJWT PyJWKClient.get_signing_key_from_jwt is affected because payload parser catches ValueError but not RecursionError. This occurs when an attacker-controlled recursively nested payload reaches json.loads. As a result, documented PyJWT exception handling does not contain the failure. Consequently, an unauthenticated request can raise an exception that may produce an HTTP 500 response. The advisory-defined affected implementation also includes jwt/api_jwt.py, verify_signature=False. This issue is fixed in version 2.15.0.(CVE-2026-101918)\n\nPyJWT is a Python implementation of JSON Web Token standards. From 2.13.0 until 2.14.0, PyJWS._load in jwt/api_jws.py is affected because parser catches ValueError but not RecursionError. This occurs when a deeply nested token header reaches json.loads. As a result, RecursionError escapes the documented PyJWT error hierarchy. Consequently, an unauthenticated malformed token can cause a request-level failure and HTTP 500. This issue is fixed in version 2.14.0.(CVE-2026-102265)\n\nPyJWT is a Python implementation of JSON Web Token standards. Prior to 2.14.0, PyJWT signature segment is affected because signature segment decoding accepts characters outside the canonical Base64URL representation. This occurs when non-Base64URL characters are appended to a valid compact JWS signature segment. As a result, base64url_decode produces the same signature bytes for different serialized segments. Consequently, raw-token revocation checks can fail to recognize an equivalent modified token. This issue is fixed in version 2.14.0.(CVE-2026-102269)\n\nPyJWT is a Python implementation of JSON Web Token standards. From 2.1.0 until 2.15.0, PyJWT OKPAlgorithm.from_jwk in  jwt/algorithms.py is affected because private-JWK import path does not compare the public key derived from d with x. This occurs when an OKP private JWK supplies non-corresponding x and d components. As a result, identity derived from x can differ from operations performed with d. Consequently, if an integration also accepts private key parameters from a proof header without rejecting them, an attacker may use a stolen sender-constrained token without the legitimate private key. This issue is fixed in version 2.15.0.(CVE-2026-102275)","status":"published","published":"2026-10-22T14:35:19Z","modified":"2026-10-22T14:45:05.435029174Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N","level":"medium"}],"updated_at":"2026-11-02T15:52:47.981622Z"},{"id":"OESA-2026-4454","title":"python-jwt security update","description":"setup.py test %endif\r\n\r\nSecurity Fix(es):\n\nPyJWT is a Python implementation of JSON Web Token standards. From 2.0.0a1 until 2.15.0, PyJWT PyJWKClient.get_signing_key_from_jwt is affected because payload parser catches ValueError but not RecursionError. This occurs when an attacker-controlled recursively nested payload reaches json.loads. As a result, documented PyJWT exception handling does not contain the failure. Consequently, an unauthenticated request can raise an exception that may produce an HTTP 500 response. The advisory-defined affected implementation also includes jwt/api_jwt.py, verify_signature=False. This issue is fixed in version 2.15.0.(CVE-2026-101918)\n\nPyJWT is a Python implementation of JSON Web Token standards. From 2.13.0 until 2.14.0, PyJWS._load in jwt/api_jws.py is affected because parser catches ValueError but not RecursionError. This occurs when a deeply nested token header reaches json.loads. As a result, RecursionError escapes the documented PyJWT error hierarchy. Consequently, an unauthenticated malformed token can cause a request-level failure and HTTP 500. This issue is fixed in version 2.14.0.(CVE-2026-102265)\n\nPyJWT is a Python implementation of JSON Web Token standards. Prior to 2.14.0, PyJWT signature segment is affected because signature segment decoding accepts characters outside the canonical Base64URL representation. This occurs when non-Base64URL characters are appended to a valid compact JWS signature segment. As a result, base64url_decode produces the same signature bytes for different serialized segments. Consequently, raw-token revocation checks can fail to recognize an equivalent modified token. This issue is fixed in version 2.14.0.(CVE-2026-102269)\n\nPyJWT is a Python implementation of JSON Web Token standards. From 2.1.0 until 2.15.0, PyJWT OKPAlgorithm.from_jwk in  jwt/algorithms.py is affected because private-JWK import path does not compare the public key derived from d with x. This occurs when an OKP private JWK supplies non-corresponding x and d components. As a result, identity derived from x can differ from operations performed with d. Consequently, if an integration also accepts private key parameters from a proof header without rejecting them, an attacker may use a stolen sender-constrained token without the legitimate private key. This issue is fixed in version 2.15.0.(CVE-2026-102275)","status":"published","published":"2026-10-22T14:35:19Z","modified":"2026-10-22T14:45:06.183628906Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N","level":"medium"}],"updated_at":"2026-11-02T15:52:47.981622Z"},{"id":"OESA-2026-4455","title":"python-jwt security update","description":"setup.py test %endif\r\n\r\nSecurity Fix(es):\n\nPyJWT is a Python implementation of JSON Web Token standards. Prior to 2.14.0, PyJWT get_signing_key_from_jwt is affected because unknown kid misses force refreshes without a negative cache or minimum refresh interval. This occurs when unauthenticated tokens repeatedly use the same unknown kid or varying kid values absent from the cached JWKS. As a result, each cache miss causes PyJWKClient to refresh the JWKS. Consequently, attacker traffic can amplify outbound requests to the configured JWKS endpoint. This issue is fixed in version 2.14.0.(CVE-2026-101917)\n\nPyJWT is a Python implementation of JSON Web Token standards. From 2.0.0a1 until 2.15.0, PyJWT PyJWKClient.get_signing_key_from_jwt is affected because payload parser catches ValueError but not RecursionError. This occurs when an attacker-controlled recursively nested payload reaches json.loads. As a result, documented PyJWT exception handling does not contain the failure. Consequently, an unauthenticated request can raise an exception that may produce an HTTP 500 response. The advisory-defined affected implementation also includes jwt/api_jwt.py, verify_signature=False. This issue is fixed in version 2.15.0.(CVE-2026-101918)\n\nPyJWT is a Python implementation of JSON Web Token standards. From 2.13.0 until 2.14.0, PyJWS._load in jwt/api_jws.py is affected because parser catches ValueError but not RecursionError. This occurs when a deeply nested token header reaches json.loads. As a result, RecursionError escapes the documented PyJWT error hierarchy. Consequently, an unauthenticated malformed token can cause a request-level failure and HTTP 500. This issue is fixed in version 2.14.0.(CVE-2026-102265)\n\nPyJWT is a Python implementation of JSON Web Token standards. Prior to 2.14.0, PyJWT signature segment is affected because signature segment decoding accepts characters outside the canonical Base64URL representation. This occurs when non-Base64URL characters are appended to a valid compact JWS signature segment. As a result, base64url_decode produces the same signature bytes for different serialized segments. Consequently, raw-token revocation checks can fail to recognize an equivalent modified token. This issue is fixed in version 2.14.0.(CVE-2026-102269)\n\nPyJWT is a Python implementation of JSON Web Token standards. From 2.1.0 until 2.15.0, PyJWT OKPAlgorithm.from_jwk in  jwt/algorithms.py is affected because private-JWK import path does not compare the public key derived from d with x. This occurs when an OKP private JWK supplies non-corresponding x and d components. As a result, identity derived from x can differ from operations performed with d. Consequently, if an integration also accepts private key parameters from a proof header without rejecting them, an attacker may use a stolen sender-constrained token without the legitimate private key. This issue is fixed in version 2.15.0.(CVE-2026-102275)","status":"published","published":"2026-10-22T14:35:20Z","modified":"2026-10-22T14:45:05.985764214Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N","level":"medium"}],"updated_at":"2026-11-02T15:52:47.981622Z"},{"id":"OESA-2026-4456","title":"python-jwt security update","description":"setup.py test %endif\r\n\r\nSecurity Fix(es):\n\nPyJWT is a Python implementation of JSON Web Token standards. Prior to 2.14.0, PyJWT get_signing_key_from_jwt is affected because unknown kid misses force refreshes without a negative cache or minimum refresh interval. This occurs when unauthenticated tokens repeatedly use the same unknown kid or varying kid values absent from the cached JWKS. As a result, each cache miss causes PyJWKClient to refresh the JWKS. Consequently, attacker traffic can amplify outbound requests to the configured JWKS endpoint. This issue is fixed in version 2.14.0.(CVE-2026-101917)\n\nPyJWT is a Python implementation of JSON Web Token standards. From 2.0.0a1 until 2.15.0, PyJWT PyJWKClient.get_signing_key_from_jwt is affected because payload parser catches ValueError but not RecursionError. This occurs when an attacker-controlled recursively nested payload reaches json.loads. As a result, documented PyJWT exception handling does not contain the failure. Consequently, an unauthenticated request can raise an exception that may produce an HTTP 500 response. The advisory-defined affected implementation also includes jwt/api_jwt.py, verify_signature=False. This issue is fixed in version 2.15.0.(CVE-2026-101918)\n\nPyJWT is a Python implementation of JSON Web Token standards. From 2.13.0 until 2.14.0, PyJWS._load in jwt/api_jws.py is affected because parser catches ValueError but not RecursionError. This occurs when a deeply nested token header reaches json.loads. As a result, RecursionError escapes the documented PyJWT error hierarchy. Consequently, an unauthenticated malformed token can cause a request-level failure and HTTP 500. This issue is fixed in version 2.14.0.(CVE-2026-102265)\n\nPyJWT is a Python implementation of JSON Web Token standards. Prior to 2.14.0, PyJWT signature segment is affected because signature segment decoding accepts characters outside the canonical Base64URL representation. This occurs when non-Base64URL characters are appended to a valid compact JWS signature segment. As a result, base64url_decode produces the same signature bytes for different serialized segments. Consequently, raw-token revocation checks can fail to recognize an equivalent modified token. This issue is fixed in version 2.14.0.(CVE-2026-102269)\n\nPyJWT is a Python implementation of JSON Web Token standards. From 2.1.0 until 2.15.0, PyJWT OKPAlgorithm.from_jwk in  jwt/algorithms.py is affected because private-JWK import path does not compare the public key derived from d with x. This occurs when an OKP private JWK supplies non-corresponding x and d components. As a result, identity derived from x can differ from operations performed with d. Consequently, if an integration also accepts private key parameters from a proof header without rejecting them, an attacker may use a stolen sender-constrained token without the legitimate private key. This issue is fixed in version 2.15.0.(CVE-2026-102275)","status":"published","published":"2026-10-22T14:35:21Z","modified":"2026-10-22T14:45:06.681086792Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N","level":"medium"}],"updated_at":"2026-11-02T15:52:47.981622Z"},{"id":"PYSEC-2026-4141","title":"PyJWT: Unauthenticated RecursionError DoS in pre-verification payload parse (PyJWKClient.get_signing_key_from_jwt / verify_signature=False)","description":"## Summary\n\n`PyJWKClient.get_signing_key_from_jwt(token)` — the first step of the JWKS\nverification flow documented in `docs/usage.rst` — must decode a token's\npayload before its signature can be checked, via\n`jwt.api_jwt.decode_complete(token, options={\"verify_signature\": False})`.\nThat call parses the payload with `json.loads` in `PyJWT._decode_payload`\n(`jwt/api_jwt.py:297-300`), whose `except` clause catches only `ValueError`.\nA payload that is valid JSON but nested ~20,000 levels deep makes\n`json.loads` raise `RecursionError`, which is **not** a `ValueError` and\nescapes as a raw, undocumented exception type — not `DecodeError`,\n`InvalidTokenError`, or `PyJWTError`, so every documented error-handling\npattern in `docs/usage.rst` misses it.\n\nThe token needs no valid signature and no network access — the crash\nhappens during payload parsing, before the `kid` is even looked up. A\nsingle unauthenticated ~50KB request crashes the caller's auth handler\n(HTTP 500 / dead worker), repeatably. The same path is reachable through\nplain `jwt.decode(token, options={\"verify_signature\": False})` too.\n\nNotably, this project already fixed the **identical** bug class for the\nJWS **header** path — `PyJWS._load` catches `(ValueError, RecursionError)`\nand wraps it in `DecodeError` (`jwt/api_jws.py:360-361`), and\n`CHANGELOG.rst` (v2.14.0, \"Security\") states \"Handle deeply nested and\nmalformed JWS/JWK input without uncaught recursion errors.\" The payload\npath — the one part of a forged token an unauthenticated attacker fully\ncontrols — was left catching `ValueError` alone, so that security fix does\nnot fully hold.\n\nA second, related instance: `PyJWKClient.fetch_data` (`jwt/jwks_client.py:168`)\nparses a JWKS endpoint's response with `json.load(response)` inside a\n`try` that only catches `(URLError, TimeoutError, http.client.HTTPException)`\n— a deeply-nested JSON response from a JWKS endpoint raises the same raw\n`RecursionError`, uncaught entirely (worse than the payload path, which at\nleast caught plain `ValueError`).\n\n**Affected versions:** confirmed present in the current release, 2.14.0,\nand on the current `master` branch (commit `4adcd02722f5011c60079d3978dfc167b9a8eaa5`).\n\n## Reproduction\n\n```python\nimport base64, json, jwt\n\ndef b64url(b):\n    return base64.urlsafe_b64encode(b).rstrip(b\"=\")\n\nheader = b64url(json.dumps({\"alg\": \"HS256\", \"typ\": \"JWT\"}).encode())\npayload = b64url(b\"[\" * 20_000 + b\"]\" * 20_000)\ntoken = (header + b\".\" + payload + b\".\" + b64url(b\"forged-sig\")).decode()\n\njwt.decode(token, options={\"verify_signature\": False})\n# raises: RecursionError (not DecodeError/InvalidTokenError/PyJWTError)\n```\n\nControl: the same deeply-nested structure moved into the token's **header**\ninstead of its payload is correctly converted to `jwt.DecodeError` by the\nalready-hardened `jwt/api_jws.py:360` — confirming the payload path is\nspecifically the missed half of the v2.14.0 hardening, not a general gap.\n\n## Impact assessment\n\nUnauthenticated denial-of-service via unhandled exception on an auth path.\nNot an auth bypass — rated medium. With signature verification enabled,\nthis parse runs after `_verify_signature`, so only the pre-verification\npaths (`get_signing_key_from_jwt`, explicit `verify_signature=False`) are\nattacker-reachable pre-auth; the JWKS-endpoint variant requires control of\n(or a MITM on) the configured JWKS endpoint rather than being reachable\nfrom an arbitrary client token.\n\n## Suggested fix\n\nIn `jwt/api_jwt.py:299`, change `except ValueError as e:` to\n`except (ValueError, RecursionError) as e:`, mirroring\n`jwt/api_jws.py:360` exactly. In `jwt/jwks_client.py`, add the same\n`(ValueError, RecursionError)` handling around `json.load(response)` in\n`fetch_data`, raising `PyJWKClientError` (consistent with the method's\nexisting documented error contract). A patch implementing both, verified\nagainst the full test suite (457 passed, 4 skipped — pre-existing,\nenvironment-related) and against the reproduction above (now correctly\nraises `DecodeError`), is attached (`fix.patch`).\n\n## Discovery method\n\nFound and verified using `scopegrep` (https://github.com/not-ekalabya/scopegrep)\n— a semantic code-retrieval tool that surfaces every other call site of a\nsymbol alongside relevance-ranked results, which is what surfaced the\nalready-hardened header path as the direct comparison here — paired with\nan LLM coding agent (GLM-5.3) run as an open-ended security review of this\nrepository. Independently reproduced against the exact commit above before\nthis report was written. Happy to share the full session transcript on\nrequest.\n\n## Disclosure status\n\nNot shared with any other party or published. Submitting through this\nprivate channel per the project's stated security policy; no planned\npublic/conference disclosure ahead of a coordinated timeline.\n\n\n---\n\n## Maintainer triage update (2026-09-22)\n\n### Confirmed finding and scope\n\nWe confirmed that an attacker-controlled recursively nested JWT payload can cause a raw Python `RecursionError` to escape PyJWT at PyJWT 2.14.0 and the tested current source. The confirmed in-scope paths are direct decoding with `verify_signature=False` and `PyJWKClient.get_signing_key_from_jwt`, where payload parsing occurs before key lookup.\n\nThe demonstrated impact is limited to an uncaught exception for the affected call, which may surface as an application HTTP 500 when the application does not catch it. Testing did not demonstrate a worker or process crash, persistent resource exhaustion, resource amplification, authentication bypass, or confidentiality or integrity impact.\n\nThe separate JWKS-response subclaim is out of scope under the policy boundary that requires the application to trust its configured JWKS source and transport. The confirmed payload finding is not a duplicate of the earlier protected-header parser finding: it occurs in a distinct payload parsing path that remained affected after the earlier header-only fix.\n\n### Version and remediation status\n\nHistorical testing reproduced the confirmed payload behavior in all 20 official supported PyJWT 2.x releases from 2.0.0a1 through 2.14.0, inclusive. Unsupported PyJWT 1.7.1 also reproduces the behavior, but it is excluded from the advisory range under the supported-2.x policy. No supported unaffected release and no patched release exists. The exact evidence is `/Users/jpadilla/.codex/security-advisories/pyjwt/GHSA-42vr-xj54-vc7v-historical-range-20260922.md` (SHA-256 `c48f1ac35641e9382d53e6a879a71ad9a8fb4432bbe871f2b8330f8d166a2d81`) and `/Users/jpadilla/.codex/security-advisories/pyjwt/historical-range-42vr-20260922/historical-range-results.json` (SHA-256 `324997f231561bf6da39b8f9d1e272f69bfde8871a7863f5cb7b70e22e91f076`). The evidence-backed supported affected range is `\u003e= 2.0.0a1, \u003c= 2.14.0`.\n\nHistorical range verification is complete. A local fix commit exists and has passed independent review and the complete local CI suite, but it has not been merged into `master` or released. Consequently, `patched_versions` remains empty and this advisory remains in `triage`. The remaining next step is a maintainer decision on remediation and merge. After a fix lands in `master` and is released, `patched_versions` and advisory lifecycle can be updated in a separate approved batch.\n\n---\n\n## Maintainer remediation update (2026-09-23)\n\nThe confirmed payload-parser finding has been fixed on `master`. Commit\n`5fde08a6cf906aa7698de2d6391d88b73006b17b` converts a recursive\npayload parse failure to the expected `DecodeError`; commit\n`9bc06658f875b9b40091539140bbbdc4639161c3` makes the regression tests\ndeterministic across supported Python versions. This update supersedes the\n2026-09-22 remediation-status statement that the fix had not landed.\n\nThe original pre-verification payload reproducer and the\n`PyJWKClient.get_signing_key_from_jwt` path were covered by regression tests.\nThe exact landed tree passed the full 39-environment local tox matrix and\nGitHub CI for commit `9bc06658f875b9b40091539140bbbdc4639161c3` passed\nall 25 jobs, including Ubuntu Python 3.14 and 3.15. The demonstrated impact\nremains an uncaught request-level exception in affected releases; there is\nstill no evidence of process termination, persistent resource exhaustion,\nauthentication bypass, or confidentiality or integrity impact.\n\nThe supported affected range remains `\u003e= 2.0.0a1, \u003c= 2.14.0`. The latest\nreleased version is 2.14.0, which predates these commits; no released\npatched version exists yet, so `patched_versions` remains unset. CVSS v3.1\n5.3 (Medium) and CWE-248 remain unchanged. The advisory may now move from\ntriage to private draft. The next lifecycle step is a new supported 2.x\nrelease containing the fix, followed by separately approved patched-version\nand publication updates after release verification.\n\n---\n\n## Maintainer release update (2026-09-23)\n\nPyJWT 2.15.0 is the first released version containing the payload-parser fix. Its GitHub release tag points to commit `1d41a6478e1562e68ff667fcd703356acf085f68`, which includes fix commit `5fde08a6cf906aa7698de2d6391d88b73006b17b` and deterministic regression-test commit `9bc06658f875b9b40091539140bbbdc4639161c3`. PyPI published both the wheel and source distribution from that release commit through the successful production workflow at https://github.com/jpadilla/pyjwt/actions/runs/35891602963.\n\nThe published PyPI wheel (`pyjwt-2.15.0-py3-none-any.whl`, SHA-256 `7a3742debf6b879e912dbb9819ceec1594be812452b78c5f2e2dfc56564954f8`) was checked directly: the deeply nested unsigned payload now raises `DecodeError`, while an ordinary unsigned payload still decodes. The supported affected range remains `\u003e= 2.0.0a1, \u003c= 2.14.0`; the patched version is `2.15.0`. Earlier statements in this advisory that no released patched version exists are superseded by this update.\n\nThe confirmed impact remains an uncaught request-level exception in affected versions, not a demonstrated process crash or authentication bypass. The separate JWKS-response subclaim remains outside this advisory's confirmed PyJWT-owned scope.","status":"published","published":"2026-10-01T16:38:41.27477Z","modified":"2026-10-01T17:45:16.836914789Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L","level":"medium"}],"updated_at":"2026-11-02T15:52:57.255153Z"},{"id":"UBUNTU-CVE-2026-101918","description":"PyJWT is a Python implementation of JSON Web Token standards. From 2.0.0a1 until 2.15.0, PyJWT PyJWKClient.get_signing_key_from_jwt is affected because payload parser catches ValueError but not RecursionError. This occurs when an attacker-controlled recursively nested payload reaches json.loads. As a result, documented PyJWT exception handling does not contain the failure. Consequently, an unauthenticated request can raise an exception that may produce an HTTP 500 response. The advisory-defined affected implementation also includes jwt/api_jwt.py, verify_signature=False. This issue is fixed in version 2.15.0.","status":"published","published":"2026-09-28T21:17:00Z","modified":"2026-10-27T11:45:03.805706168Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L","level":"medium"},{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T16:55:58.519486Z"},{"id":"AZL-105218","title":"CVE-2026-101918 affecting package python-jwt for versions less than 2.15.1-1","description":"PyJWT is a Python implementation of JSON Web Token standards. From 2.0.0a1 until 2.15.0, PyJWT PyJWKClient.get_signing_key_from_jwt is affected because payload parser catches ValueError but not RecursionError. This occurs when an attacker-controlled recursively nested payload reaches json.loads. As a result, documented PyJWT exception handling does not contain the failure. Consequently, an unauthenticated request can raise an exception that may produce an HTTP 500 response. The advisory-defined affected implementation also includes jwt/api_jwt.py, verify_signature=False. This issue is fixed in version 2.15.0.","status":"published","published":"2026-09-28T21:17:13Z","modified":"2026-11-02T14:17:22.683079163Z","updated_at":"2026-11-02T15:28:01.09948Z"},{"id":"CLSA-2026-1791271338","title":"TuxCare security update for pyjwt (7 CVEs)","description":"TuxCare rebuilt pyjwt to address 7 CVEs. Fixed in 2.3.0.post4+tuxcare.","status":"published","published":"2026-10-06T07:22:18Z","modified":"2026-10-15T09:48:07.255854927Z","updated_at":"2026-11-02T15:43:49.016976Z"},{"id":"CLSA-2026-1791272473","title":"TuxCare security update for pyjwt (2 CVEs)","description":"TuxCare rebuilt pyjwt to address 2 CVEs. Fixed in 2.10.1.post6+tuxcare.","status":"published","published":"2026-10-06T07:41:13Z","modified":"2026-10-15T09:48:07.217180052Z","updated_at":"2026-11-02T15:43:49.016976Z"},{"id":"CLSA-2026-1791272714","title":"TuxCare security update for pyjwt (2 CVEs)","description":"TuxCare rebuilt pyjwt to address 2 CVEs. Fixed in 2.8.0.post5+tuxcare.","status":"published","published":"2026-10-06T07:45:14Z","modified":"2026-10-15T09:46:21.707898092Z","updated_at":"2026-11-02T15:43:49.016976Z"},{"id":"openSUSE-SU-2026:11994-1","title":"python313-PyJWT-2.15.1-1.1 on GA media","description":"These are all security issues fixed in the python313-PyJWT-2.15.1-1.1 package on the GA media of openSUSE Tumbleweed.","status":"published","published":"2026-10-04T00:00:00Z","modified":"2026-10-05T10:15:15.811415752Z","updated_at":"2026-11-02T16:58:40.245664Z"},{"id":"openSUSE-SU-2026:22074-1","title":"Security update for python-PyJWT","description":"This update for python-PyJWT fixes the following issues:\n\n- CVE-2026-101917: attacker traffic can amplify outbound requests to the configured JWKS endpoint (bsc#1283060).\n- CVE-2026-101918: unauthenticated request can raise an exception that may produce an HTTP 500 response (bsc#1283061).\n- CVE-2026-102267: forwarded credentials may be disclosed or verification keys may be substituted (bsc#1283064).\n- CVE-2026-102268: an attacker who knows the public key can forge authenticated HMAC tokens (bsc#1283065).\n- CVE-2026-102269: raw-token revocation checks can fail to recognize an equivalent modified token (bsc#1283066).\n- CVE-2026-102270: an attacker can cause intensive CPU consumption (bsc#1283067).\n- CVE-2026-102271: an attacker who knows the public key can forge authenticated HMAC tokens (bsc#1283068).\n- CVE-2026-102274: Malformed RSA JWK aborts parsing of an entire JWK Set (bsc#1283071).\n- CVE-2026-102275: an attacker may use a stolen sender-constrained token without the legitimate private key\n  (bsc#1283072).\n- CVE-2026-103001: reused mutable options mapping can cause verification checks bypass on subsequent decode calls\n  (bsc#1283829).\n","status":"published","published":"2026-10-09T12:17:21Z","modified":"2026-10-19T17:23:12.597526095Z","updated_at":"2026-11-02T16:58:42.426393Z"},{"id":"SUSE-SU-2026:24126-1","title":"Security update for python-PyJWT","description":"This update for python-PyJWT fixes the following issues:\n\n- CVE-2026-101917: attacker traffic can amplify outbound requests to the configured JWKS endpoint (bsc#1283060).\n- CVE-2026-101918: unauthenticated request can raise an exception that may produce an HTTP 500 response (bsc#1283061).\n- CVE-2026-102267: forwarded credentials may be disclosed or verification keys may be substituted (bsc#1283064).\n- CVE-2026-102268: an attacker who knows the public key can forge authenticated HMAC tokens (bsc#1283065).\n- CVE-2026-102269: raw-token revocation checks can fail to recognize an equivalent modified token (bsc#1283066).\n- CVE-2026-102270: an attacker can cause intensive CPU consumption (bsc#1283067).\n- CVE-2026-102271: an attacker who knows the public key can forge authenticated HMAC tokens (bsc#1283068).\n- CVE-2026-102274: Malformed RSA JWK aborts parsing of an entire JWK Set (bsc#1283071).\n- CVE-2026-102275: an attacker may use a stolen sender-constrained token without the legitimate private key\n  (bsc#1283072).\n- CVE-2026-103001: reused mutable options mapping can cause verification checks bypass on subsequent decode calls\n  (bsc#1283829).\n","status":"published","published":"2026-10-09T12:13:13Z","modified":"2026-10-13T17:23:10.206484436Z","updated_at":"2026-11-02T15:54:04.519245Z"},{"id":"SUSE-SU-2026:24134-1","title":"Security update for python-PyJWT","description":"This update for python-PyJWT fixes the following issues:\n\n- CVE-2026-101917: attacker traffic can amplify outbound requests to the configured JWKS endpoint (bsc#1283060).\n- CVE-2026-101918: unauthenticated request can raise an exception that may produce an HTTP 500 response (bsc#1283061).\n- CVE-2026-102267: forwarded credentials may be disclosed or verification keys may be substituted (bsc#1283064).\n- CVE-2026-102268: an attacker who knows the public key can forge authenticated HMAC tokens (bsc#1283065).\n- CVE-2026-102269: raw-token revocation checks can fail to recognize an equivalent modified token (bsc#1283066).\n- CVE-2026-102270: an attacker can cause intensive CPU consumption (bsc#1283067).\n- CVE-2026-102271: an attacker who knows the public key can forge authenticated HMAC tokens (bsc#1283068).\n- CVE-2026-102274: Malformed RSA JWK aborts parsing of an entire JWK Set (bsc#1283071).\n- CVE-2026-102275: an attacker may use a stolen sender-constrained token without the legitimate private key\n  (bsc#1283072).\n","status":"published","published":"2026-10-09T11:50:01Z","modified":"2026-10-15T17:23:11.683497084Z","updated_at":"2026-11-02T15:54:04.519245Z"},{"id":"SUSE-SU-2026:24219-1","title":"Security update for python-PyJWT","description":"This update for python-PyJWT fixes the following issues:\n\n- CVE-2026-101917: attacker traffic can amplify outbound requests to the configured JWKS endpoint (bsc#1283060).\n- CVE-2026-101918: unauthenticated request can raise an exception that may produce an HTTP 500 response (bsc#1283061).\n- CVE-2026-102267: forwarded credentials may be disclosed or verification keys may be substituted (bsc#1283064).\n- CVE-2026-102268: an attacker who knows the public key can forge authenticated HMAC tokens (bsc#1283065).\n- CVE-2026-102269: raw-token revocation checks can fail to recognize an equivalent modified token (bsc#1283066).\n- CVE-2026-102270: an attacker can cause intensive CPU consumption (bsc#1283067).\n- CVE-2026-102271: an attacker who knows the public key can forge authenticated HMAC tokens (bsc#1283068).\n- CVE-2026-102274: Malformed RSA JWK aborts parsing of an entire JWK Set (bsc#1283071).\n- CVE-2026-102275: an attacker may use a stolen sender-constrained token without the legitimate private key\n  (bsc#1283072).\n- CVE-2026-103001: reused mutable options mapping can cause verification checks bypass on subsequent decode calls\n  (bsc#1283829).\n","status":"published","published":"2026-10-09T12:13:13Z","modified":"2026-10-21T17:23:10.838650728Z","updated_at":"2026-11-02T15:54:04.519245Z"},{"id":"SUSE-SU-2026:24377-1","title":"Security update for python-PyJWT","description":"This update for python-PyJWT fixes the following issues:\n\n- CVE-2026-101917: attacker traffic can amplify outbound requests to the configured JWKS endpoint (bsc#1283060).\n- CVE-2026-101918: unauthenticated request can raise an exception that may produce an HTTP 500 response (bsc#1283061).\n- CVE-2026-102267: forwarded credentials may be disclosed or verification keys may be substituted (bsc#1283064).\n- CVE-2026-102268: an attacker who knows the public key can forge authenticated HMAC tokens (bsc#1283065).\n- CVE-2026-102269: raw-token revocation checks can fail to recognize an equivalent modified token (bsc#1283066).\n- CVE-2026-102270: an attacker can cause intensive CPU consumption (bsc#1283067).\n- CVE-2026-102271: an attacker who knows the public key can forge authenticated HMAC tokens (bsc#1283068).\n- CVE-2026-102274: Malformed RSA JWK aborts parsing of an entire JWK Set (bsc#1283071).\n- CVE-2026-102275: an attacker may use a stolen sender-constrained token without the legitimate private key\n  (bsc#1283072).\n- CVE-2026-103001: reused mutable options mapping can cause verification checks bypass on subsequent decode calls\n  (bsc#1283829).\n","status":"published","published":"2026-10-20T15:12:20Z","modified":"2026-10-27T17:23:19.403372208Z","updated_at":"2026-11-02T15:54:04.519245Z"},{"id":"SUSE-SU-2026:5064-1","title":"Security update for python-PyJWT","description":"This update for python-PyJWT fixes the following issues:\n\n- CVE-2026-101917: attacker traffic can amplify outbound requests to the configured JWKS endpoint (bsc#1283060).\n- CVE-2026-101918: unauthenticated request can raise an exception that may produce an HTTP 500 response (bsc#1283061).\n- CVE-2026-102267: forwarded credentials may be disclosed or verification keys may be substituted (bsc#1283064).\n- CVE-2026-102268: an attacker who knows the public key can forge authenticated HMAC tokens (bsc#1283065).\n- CVE-2026-102269: raw-token revocation checks can fail to recognize an equivalent modified token (bsc#1283066).\n- CVE-2026-102270: an attacker can cause intensive CPU consumption (bsc#1283067).\n- CVE-2026-102271: an attacker who knows the public key can forge authenticated HMAC tokens (bsc#1283068).\n- CVE-2026-102275: an attacker may use a stolen sender-constrained token without the legitimate private key\n  (bsc#1283072).\n","status":"published","published":"2026-11-03T07:32:38Z","modified":"2026-11-03T22:45:04.564059533Z","updated_at":"2026-11-03T22:59:30.419462Z"},{"id":"USN-8934-1","title":"pyjwt vulnerabilities","description":"Kingsley Olukanni discovered that PyJWT did not properly handle unknown key\nidentifiers when retrieving signing keys. An attacker could possibly use\nthis issue to amplify requests to the configured key endpoint, resulting in\na denial of service. This issue only affected Ubuntu 22.04 LTS, Ubuntu\n24.04 LTS, Ubuntu 26.04 LTS and Ubuntu 26.10. (CVE-2026-101917)\n\nEkalabya Ghosh discovered that PyJWT did not properly handle certain\nrecursively nested JSON payloads. An attacker could possibly use this issue\nto cause an application to fail, resulting in a denial of service.\n(CVE-2026-101918)\n\nPedram Hayati discovered that PyJWT did not properly handle malformed RSA\nkeys in a JSON Web Key Set. An attacker could possibly use this issue to\ncause authentication failures or a denial of service. This issue only\naffected Ubuntu 22.04 LTS, Ubuntu 24.04 LTS,  Ubuntu 26.04 LTS and Ubuntu\n26.10. (CVE-2026-102274)\n\nIt was discovered that PyJWT did not properly validate certain OKP private\nkey components. An attacker could possibly use this issue to confuse the\nidentity of public and private keys, and use a stolen sender-constrained\ntoken without the legitimate private key. This issue only affected Ubuntu\n22.04 LTS, Ubuntu 24.04 LTS, Ubuntu 26.04 LTS and Ubuntu 26.10.\n(CVE-2026-102275)","status":"published","published":"2026-10-19T19:00:51Z","modified":"2026-10-27T11:56:51.36453097Z","updated_at":"2026-11-02T16:58:26.907654Z"}]}}
