Action not permitted
Modal body text goes here.
Modal Title
Modal Body
CVE-2026-48525 (GCVE-0-2026-48525)
Vulnerability from cvelistv5 – Published: 2026-05-28 15:11 – Updated: 2026-05-28 15:59- CWE-400 - Uncontrolled Resource Consumption
| URL | Tags |
|---|---|
| https://github.com/jpadilla/pyjwt/security/adviso… | x_refsource_CONFIRM |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-48525",
"options": [
{
"Exploitation": "poc"
},
{
"Automatable": "yes"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-05-28T15:58:48.873096Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-05-28T15:59:19.219Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"references": [
{
"tags": [
"exploit"
],
"url": "https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39"
}
],
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"product": "pyjwt",
"vendor": "jpadilla",
"versions": [
{
"status": "affected",
"version": "\u003e= 2.8.0, \u003c 2.13.0"
}
]
}
],
"descriptions": [
{
"lang": "en",
"value": "PyJWT is a JSON Web Token implementation in Python. From 2.8.0 to 2.12.1, when verifying detached JWS tokens using the unencoded-payload option (\"b64\": false, RFC 7797), PyJWT performs Base64URL decoding of the compact-serialization payload segment before enforcing the detached-payload rules. For b64=false, PyJWT later discards that decoded payload and replaces it with the caller-provided detached_payload. In practice, this turns the middle segment into an attacker-controlled \u201cwork amplifier\u201d: a remote client can supply an arbitrarily large Base64URL payload segment that forces CPU work + memory allocations even if the signature is invalid. This creates an unauthenticated DoS vector against any endpoint that verifies detached JWS using PyJWT. This vulnerability is fixed in 2.13.0."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "LOW",
"baseScore": 5.3,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "NONE",
"integrityImpact": "NONE",
"privilegesRequired": "NONE",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"version": "3.1"
}
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-400",
"description": "CWE-400: Uncontrolled Resource Consumption",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-05-28T15:11:12.483Z",
"orgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"shortName": "GitHub_M"
},
"references": [
{
"name": "https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39",
"tags": [
"x_refsource_CONFIRM"
],
"url": "https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39"
}
],
"source": {
"advisory": "GHSA-w7vc-732c-9m39",
"discovery": "UNKNOWN"
},
"title": "PyJWT: Unauthenticated DoS via unbounded Base64URL decoding of unused payload segment in b64=false detached JWS"
}
},
"cveMetadata": {
"assignerOrgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"assignerShortName": "GitHub_M",
"cveId": "CVE-2026-48525",
"datePublished": "2026-05-28T15:11:12.483Z",
"dateReserved": "2026-05-21T16:18:10.619Z",
"dateUpdated": "2026-05-28T15:59:19.219Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2",
"vulnerability-lookup:meta": {
"epss": {
"cve": "CVE-2026-48525",
"date": "2026-06-16",
"epss": "0.0025",
"percentile": "0.16109"
},
"nvd": "{\"cve\":{\"id\":\"CVE-2026-48525\",\"sourceIdentifier\":\"security-advisories@github.com\",\"published\":\"2026-05-28T16:16:29.533\",\"lastModified\":\"2026-06-01T17:45:15.763\",\"vulnStatus\":\"Analyzed\",\"cveTags\":[],\"descriptions\":[{\"lang\":\"en\",\"value\":\"PyJWT is a JSON Web Token implementation in Python. From 2.8.0 to 2.12.1, when verifying detached JWS tokens using the unencoded-payload option (\\\"b64\\\": false, RFC 7797), PyJWT performs Base64URL decoding of the compact-serialization payload segment before enforcing the detached-payload rules. For b64=false, PyJWT later discards that decoded payload and replaces it with the caller-provided detached_payload. In practice, this turns the middle segment into an attacker-controlled \u201cwork amplifier\u201d: a remote client can supply an arbitrarily large Base64URL payload segment that forces CPU work + memory allocations even if the signature is invalid. This creates an unauthenticated DoS vector against any endpoint that verifies detached JWS using PyJWT. This vulnerability is fixed in 2.13.0.\"}],\"metrics\":{\"cvssMetricV31\":[{\"source\":\"security-advisories@github.com\",\"type\":\"Secondary\",\"cvssData\":{\"version\":\"3.1\",\"vectorString\":\"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L\",\"baseScore\":5.3,\"baseSeverity\":\"MEDIUM\",\"attackVector\":\"NETWORK\",\"attackComplexity\":\"LOW\",\"privilegesRequired\":\"NONE\",\"userInteraction\":\"NONE\",\"scope\":\"UNCHANGED\",\"confidentialityImpact\":\"NONE\",\"integrityImpact\":\"NONE\",\"availabilityImpact\":\"LOW\"},\"exploitabilityScore\":3.9,\"impactScore\":1.4}]},\"weaknesses\":[{\"source\":\"security-advisories@github.com\",\"type\":\"Secondary\",\"description\":[{\"lang\":\"en\",\"value\":\"CWE-400\"}]}],\"configurations\":[{\"nodes\":[{\"operator\":\"OR\",\"negate\":false,\"cpeMatch\":[{\"vulnerable\":true,\"criteria\":\"cpe:2.3:a:pyjwt_project:pyjwt:*:*:*:*:*:*:*:*\",\"versionStartIncluding\":\"2.8.0\",\"versionEndIncluding\":\"2.12.1\",\"matchCriteriaId\":\"71DC0C43-352F-449C-B411-5040A311A35F\"}]}]}],\"references\":[{\"url\":\"https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39\",\"source\":\"security-advisories@github.com\",\"tags\":[\"Exploit\",\"Vendor Advisory\",\"Mitigation\"]},{\"url\":\"https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39\",\"source\":\"134c704f-9b21-4f2e-91b3-4a467353bcc0\",\"tags\":[\"Exploit\",\"Vendor Advisory\",\"Mitigation\"]}]}}"
}
}
FKIE_CVE-2026-48525
Vulnerability from fkie_nvd - Published: 2026-05-28 16:16 - Updated: 2026-06-01 17:45| URL | Tags | ||
|---|---|---|---|
| security-advisories@github.com | https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39 | Exploit, Vendor Advisory, Mitigation | |
| 134c704f-9b21-4f2e-91b3-4a467353bcc0 | https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39 | Exploit, Vendor Advisory, Mitigation |
| Vendor | Product | Version | |
|---|---|---|---|
| pyjwt_project | pyjwt | * |
{
"configurations": [
{
"nodes": [
{
"cpeMatch": [
{
"criteria": "cpe:2.3:a:pyjwt_project:pyjwt:*:*:*:*:*:*:*:*",
"matchCriteriaId": "71DC0C43-352F-449C-B411-5040A311A35F",
"versionEndIncluding": "2.12.1",
"versionStartIncluding": "2.8.0",
"vulnerable": true
}
],
"negate": false,
"operator": "OR"
}
]
}
],
"cveTags": [],
"descriptions": [
{
"lang": "en",
"value": "PyJWT is a JSON Web Token implementation in Python. From 2.8.0 to 2.12.1, when verifying detached JWS tokens using the unencoded-payload option (\"b64\": false, RFC 7797), PyJWT performs Base64URL decoding of the compact-serialization payload segment before enforcing the detached-payload rules. For b64=false, PyJWT later discards that decoded payload and replaces it with the caller-provided detached_payload. In practice, this turns the middle segment into an attacker-controlled \u201cwork amplifier\u201d: a remote client can supply an arbitrarily large Base64URL payload segment that forces CPU work + memory allocations even if the signature is invalid. This creates an unauthenticated DoS vector against any endpoint that verifies detached JWS using PyJWT. This vulnerability is fixed in 2.13.0."
}
],
"id": "CVE-2026-48525",
"lastModified": "2026-06-01T17:45:15.763",
"metrics": {
"cvssMetricV31": [
{
"cvssData": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "LOW",
"baseScore": 5.3,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "NONE",
"integrityImpact": "NONE",
"privilegesRequired": "NONE",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"version": "3.1"
},
"exploitabilityScore": 3.9,
"impactScore": 1.4,
"source": "security-advisories@github.com",
"type": "Secondary"
}
]
},
"published": "2026-05-28T16:16:29.533",
"references": [
{
"source": "security-advisories@github.com",
"tags": [
"Exploit",
"Vendor Advisory",
"Mitigation"
],
"url": "https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39"
},
{
"source": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"tags": [
"Exploit",
"Vendor Advisory",
"Mitigation"
],
"url": "https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39"
}
],
"sourceIdentifier": "security-advisories@github.com",
"vulnStatus": "Analyzed",
"weaknesses": [
{
"description": [
{
"lang": "en",
"value": "CWE-400"
}
],
"source": "security-advisories@github.com",
"type": "Secondary"
}
]
}
GHSA-W7VC-732C-9M39
Vulnerability from github – Published: 2026-06-15 19:29 – Updated: 2026-06-15 19:29[!NOTE] Practical impact depends on whether request body-size limits are enforced upstream (proxy/web-server/framework). Deployments with typical body-size caps (≤2 MB) bound the amplifier significantly; deployments accepting larger token inputs are more exposed.
When verifying detached JWS tokens using the unencoded-payload option ("b64": false, RFC 7797), PyJWT performs Base64URL decoding of the compact-serialization payload segment before enforcing the detached-payload rules.
For b64=false, PyJWT later discards that decoded payload and replaces it with the caller-provided detached_payload. In practice, this turns the middle segment into an attacker-controlled “work amplifier”: a remote client can supply an arbitrarily large Base64URL payload segment that forces CPU work + memory allocations even if the signature is invalid.
This creates an unauthenticated DoS vector against any endpoint that verifies detached JWS using PyJWT.
Affected Component(s)
-
jwt/api_jws.py -
PyJWS.decode()/PyJWS.decode_complete() _load()(parsing and Base64URL decoding)
Root Cause (exact logic flaw)
What happens in the code
In jwt/api_jws.py, decode_complete() does the following (order matters):
- Calls
_load(jwt)first, which decodes the token segments - Only after that, checks
header.get("b64")and ifFalse, it replacespayload = detached_payloadand rebuilds the signing input
This behavior is visible in decode_complete():
_load(jwt)happens before theb64=falsehandling- then
payload = detached_payloadandsigning_input = ... detached_payloadhappens afterward ([GitHub][1])
Inside _load(), PyJWT unconditionally performs:
payload = base64url_decode(payload_segment)This is the expensive step the attacker can amplify ([GitHub][1])
Why this becomes a vulnerability
For b64=false detached JWS, the payload segment in compact form is effectively not needed for verification in PyJWT’s own logic (since the library uses detached_payload as the real payload). Yet PyJWT still decodes it first, meaning:
- cost is paid even when signature is invalid
- the decoded bytes are discarded
- attacker controls the size of this cost via token length
Impact (evidence-driven)
Security impact
- Unauthenticated remote DoS: decoding work happens before signature rejection → attacker does not need signing key.
- CPU amplification: Base64URL decode time scales linearly with payload segment size.
- Memory amplification: decoded output allocates large byte buffers (tens of MB per request).
- Operational impact: request queueing / worker starvation under modest concurrency bursts.
Standards context (RFC 7797)
RFC 7797 explicitly notes this option is used when payload is large and/or detached, and discusses interoperability requirements around marking it critical (“crit” with “b64”). ([IETF Datatracker][2])
(PyJWT supports crit validation, but the issue here is decode order / unbounded decode of an unused segment.)
Affected Versions
- Confirmed affected: PyJWT 2.12.1 (tested from your local editable install and repo).
- Likely affected: all versions that include detached payload support for JWS decoding, which was introduced in 2.4.0 (“Add detached payload support for JWS encoding and decoding”). ([pyjwt.readthedocs.io][3])
(For GHSA, this phrasing is strong: “confirmed” + “likely since feature introduction”.)
Threat Model
Typical real deployment
A service verifies signed HTTP requests or webhooks using detached JWS:
- token is provided in JSON body / query / header
- actual payload is the HTTP request body passed as
detached_payload
Attacker
- remote unauthenticated client
- can send requests to verify endpoint
- does not need a valid signature (invalid signature still triggers the expensive decode path)
Attack chain
- Attacker crafts a JWS compact token with header containing
"b64": falseandcrit:["b64"]. - Attacker inflates the payload segment (middle segment) to millions of Base64URL characters.
- Server calls
PyJWS.decode(...detached_payload=...). - PyJWT decodes the inflated segment (CPU + memory).
- Signature is rejected afterward (401) — but resources already consumed.
- Repeated requests or bursts cause queueing/worker starvation → DoS.
Proof of Concept - file names + results
PoC placement
PoC # 1 - Localhost verification server
File: server_localhost.py
Purpose: real HTTP endpoint (POST /verify) that calls PyJWT detached verification and prints:
ok / time_ms / peak_bytes / token_len / error.
Results (server console output)
[+] Listening on http://127.0.0.1:8000
[+] POST /verify JSON: {"token": "..."}
[127.0.0.1] ok=True time_ms=0.102 peak_bytes=2624 token_len=117 err=None
[127.0.0.1] ok=False time_ms=2.012 peak_bytes=2000983 token_len=500078 err=InvalidSignatureError
[127.0.0.1] ok=True time_ms=1.591 peak_bytes=2001061 token_len=500117 err=None
[127.0.0.1] ok=True time_ms=0.065 peak_bytes=2304 token_len=117 err=None
[127.0.0.1] ok=False time_ms=7.534 peak_bytes=8000983 token_len=2000078 err=InvalidSignatureError
[127.0.0.1] ok=True time_ms=6.347 peak_bytes=8001061 token_len=2000117 err=None
[127.0.0.1] ok=True time_ms=0.066 peak_bytes=2304 token_len=117 err=None
[127.0.0.1] ok=False time_ms=23.034 peak_bytes=32000983 token_len=8000078 err=InvalidSignatureError
[127.0.0.1] ok=True time_ms=22.097 peak_bytes=32001061 token_len=8000117 err=None
Key takeaways from these results
-
At 8,000,000 chars, a single invalid-signature request still causes:
-
~23 ms server work
- ~32 MB peak allocations
- returns 401 (invalid signature) → attacker does not need key.
PoC # 2 - Localhost network client
File: client_localhost.py Purpose: generates baseline + (invalid signature) + (valid signature) tokens and sends them over HTTP to localhost server.
Results (client output)
payload-chars = 500,000
=== BASELINE (valid b64=false token) ===
HTTP: 200
client_wall_ms: 6.3499...
server_time_ms: 0.10197...
server_peak_bytes: 2624
=== ATTACK (INVALID signature - attacker needs no key) ===
HTTP: 401
client_wall_ms: 4.1010...
server_time_ms: 2.01217...
server_peak_bytes: 2000983
error: InvalidSignatureError
=== ATTACK (VALID signature - accepted path still wastes) ===
HTTP: 200
client_wall_ms: 3.6586...
server_time_ms: 1.59092...
server_peak_bytes: 2001061
payload-chars = 2,000,000
=== BASELINE ===
HTTP: 200
server_time_ms: 0.06527...
server_peak_bytes: 2304
=== ATTACK (INVALID signature) ===
HTTP: 401
server_time_ms: 7.53430...
server_peak_bytes: 8000983
=== ATTACK (VALID signature) ===
HTTP: 200
server_time_ms: 6.34682...
server_peak_bytes: 8001061
payload-chars = 8,000,000
=== BASELINE ===
HTTP: 200
server_time_ms: 0.06573...
server_peak_bytes: 2304
=== ATTACK (INVALID signature) ===
HTTP: 401
server_time_ms: 23.03403...
server_peak_bytes: 32000983
=== ATTACK (VALID signature) ===
HTTP: 200
server_time_ms: 22.09702...
server_peak_bytes: 32001061
Why this is strong evidence
- The server clearly does heavy work before rejecting invalid signatures.
- The “valid signature” case shows even accepted requests waste resources due to unused payload segment.
PoC # 3 - Localhost flood / burst concurrency
File: flood_localhost.py Purpose: sends N concurrent invalid-signature requests over HTTP to demonstrate queueing/worker starvation.
Results (your run: 20 concurrent @ 8,000,000 chars)
total_wall_ms: 1374.5405770000616
(16, 401, 1156.4504789998864, 21.350951999920653, 32000983, 'InvalidSignatureError')
(19, 401, 1151.2852699997893, 21.208721999755653, 32000983, 'InvalidSignatureError')
(18, 401, 1102.7211239997996, 21.685218999664357, 32000983, 'InvalidSignatureError')
(13, 401, 1102.0718189997751, 21.26572200040755, 32000983, 'InvalidSignatureError')
(11, 401, 1095.9345460000804, 20.586017000368884, 32000983, 'InvalidSignatureError')
(17, 401, 1085.2552810001725, 22.893039000337012, 32000983, 'InvalidSignatureError')
(10, 401, 1078.3629560000918, 22.737160999895423, 32000983, 'InvalidSignatureError')
(7, 401, 1048.2011740000416, 22.476282000297942, 32000983, 'InvalidSignatureError')
(8, 401, 378.93017700025666, 21.377330999712285, 32000983, 'InvalidSignatureError')
(1, 401, 281.45106800002395, 21.34223099983501, 32000983, 'InvalidSignatureError')
Interpretation
- Each request still costs ~20–23 ms server processing and ~32 MB peak allocations.
- But client-observed latency rises up to ~1.15 seconds because requests queue behind each other → clear worker starvation/HoL blocking.
- All were rejected with 401 InvalidSignatureError → still unauthenticated.
Fix
Goal
Prevent unbounded resource consumption from an attacker-controlled payload segment that is unused in b64=false detached flow.
Minimal change strategy
In _load() (or by refactoring parse order), do not Base64-decode payload_segment until after you know whether b64=false applies.
Two safe options:
-
Reject non-empty payload segment when
b64=false -
Parse header first
- If
b64is false andpayload_segmentis non-empty → raiseDecodeErrorbefore decoding -
Then verification uses
detached_payloadonly -
Skip decoding payload segment entirely when
b64=false -
Keep payload segment as raw bytes or empty
- Use detached payload for signing input
This aligns with the idea that detached payload is the trusted payload input for verification; the compact payload segment should not become a resource amplification vector.
(Implementation context: the current decode order and unconditional base64url_decode(payload_segment) are visible in the file and line region around _load() and decode_complete() ([GitHub][1]).)
Workarounds
- Enforce strict max token length at the HTTP boundary (proxy/gateway).
- Apply rate limiting on verification endpoints.
- If detached JWS (
b64=false) is not needed in your app, reject tokens where header includes"b64": false.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.12.1"
},
"package": {
"ecosystem": "PyPI",
"name": "pyjwt"
},
"ranges": [
{
"events": [
{
"introduced": "2.8.0"
},
{
"fixed": "2.13.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-48525"
],
"database_specific": {
"cwe_ids": [
"CWE-400"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-15T19:29:12Z",
"nvd_published_at": "2026-05-28T16:16:29Z",
"severity": "MODERATE"
},
"details": "\u003e [!NOTE]\n\u003e Practical impact depends on whether request body-size limits are enforced upstream (proxy/web-server/framework). Deployments with typical body-size caps (\u22642 MB) bound the amplifier significantly; deployments accepting larger token inputs are more exposed.\n\nWhen verifying detached JWS tokens using the unencoded-payload option (`\"b64\": false`, RFC 7797), PyJWT performs **Base64URL decoding of the compact-serialization payload segment** *before* enforcing the detached-payload rules.\n\nFor `b64=false`, PyJWT later **discards** that decoded payload and replaces it with the caller-provided `detached_payload`. In practice, this turns the middle segment into an attacker-controlled \u201cwork amplifier\u201d: a remote client can supply an arbitrarily large Base64URL payload segment that forces **CPU work + memory allocations** even if the signature is invalid.\n\nThis creates an **unauthenticated DoS** vector against any endpoint that verifies detached JWS using PyJWT.\n\n---\n\n## Affected Component(s)\n\n* `jwt/api_jws.py`\n\n * `PyJWS.decode()` / `PyJWS.decode_complete()`\n * `_load()` (parsing and Base64URL decoding)\n\n---\n\n## Root Cause (exact logic flaw)\n\n### What happens in the code\n\nIn `jwt/api_jws.py`, `decode_complete()` does the following (order matters):\n\n* Calls `_load(jwt)` first, which decodes the token segments\n* Only after that, checks `header.get(\"b64\")` and if `False`, it replaces `payload = detached_payload` and rebuilds the signing input\n\nThis behavior is visible in `decode_complete()`:\n\n* `_load(jwt)` happens **before** the `b64=false` handling\n* then `payload = detached_payload` and `signing_input = ... detached_payload` happens afterward ([GitHub][1])\n\nInside `_load()`, PyJWT unconditionally performs:\n\n* `payload = base64url_decode(payload_segment)`\n This is the expensive step the attacker can amplify ([GitHub][1])\n\n### Why this becomes a vulnerability\n\nFor `b64=false` detached JWS, the payload segment in compact form is effectively **not needed** for verification in PyJWT\u2019s own logic (since the library uses `detached_payload` as the real payload). Yet PyJWT still decodes it first, meaning:\n\n* cost is paid **even when signature is invalid**\n* the decoded bytes are **discarded**\n* attacker controls the size of this cost via token length\n\n---\n\n## Impact (evidence-driven)\n\n### Security impact\n\n* **Unauthenticated remote DoS**: decoding work happens before signature rejection \u2192 attacker does not need signing key.\n* **CPU amplification**: Base64URL decode time scales linearly with payload segment size.\n* **Memory amplification**: decoded output allocates large byte buffers (tens of MB per request).\n* **Operational impact**: request queueing / worker starvation under modest concurrency bursts.\n\n### Standards context (RFC 7797)\n\nRFC 7797 explicitly notes this option is used when payload is large and/or detached, and discusses interoperability requirements around marking it critical (\u201ccrit\u201d with \u201cb64\u201d). ([IETF Datatracker][2])\n(PyJWT supports `crit` validation, but the issue here is decode order / unbounded decode of an unused segment.)\n\n---\n\n## Affected Versions\n\n* **Confirmed affected:** PyJWT **2.12.1** (tested from your local editable install and repo).\n* **Likely affected:** all versions that include detached payload support for JWS decoding, which was introduced in **2.4.0** (\u201cAdd detached payload support for JWS encoding and decoding\u201d). ([pyjwt.readthedocs.io][3])\n\n(For GHSA, this phrasing is strong: \u201cconfirmed\u201d + \u201clikely since feature introduction\u201d.)\n\n---\n\n# Threat Model \n\n### Typical real deployment\n\nA service verifies signed HTTP requests or webhooks using detached JWS:\n\n* token is provided in JSON body / query / header\n* actual payload is the HTTP request body passed as `detached_payload`\n\n### Attacker\n\n* remote unauthenticated client\n* can send requests to verify endpoint\n* does **not** need a valid signature (invalid signature still triggers the expensive decode path)\n\n### Attack chain\n\n1. Attacker crafts a JWS compact token with header containing `\"b64\": false` and `crit:[\"b64\"]`.\n2. Attacker inflates the **payload segment** (middle segment) to millions of Base64URL characters.\n3. Server calls `PyJWS.decode(...detached_payload=...)`.\n4. PyJWT decodes the inflated segment (CPU + memory).\n5. Signature is rejected afterward (401) \u2014 but resources already consumed.\n6. Repeated requests or bursts cause queueing/worker starvation \u2192 DoS.\n\n---\n\n# Proof of Concept - file names + results\n\n## PoC placement \n\n* [server_localhost.py](https://github.com/user-attachments/files/26132755/server_localhost.py)\n\n* [client_localhost.py](https://github.com/user-attachments/files/26132757/client_localhost.py)\n\n* [flood_localhost.py](https://github.com/user-attachments/files/26132760/flood_localhost.py)\n\n\n---\n\n## PoC # 1 - Localhost verification server\n\n**File:** [server_localhost.py](https://github.com/user-attachments/files/26132755/server_localhost.py)\n\n**Purpose:** real HTTP endpoint (`POST /verify`) that calls PyJWT detached verification and prints:\n`ok / time_ms / peak_bytes / token_len / error`.\n\n### Results (server console output)\n\n```text\n[+] Listening on http://127.0.0.1:8000\n[+] POST /verify JSON: {\"token\": \"...\"}\n\n[127.0.0.1] ok=True time_ms=0.102 peak_bytes=2624 token_len=117 err=None\n[127.0.0.1] ok=False time_ms=2.012 peak_bytes=2000983 token_len=500078 err=InvalidSignatureError\n[127.0.0.1] ok=True time_ms=1.591 peak_bytes=2001061 token_len=500117 err=None\n\n[127.0.0.1] ok=True time_ms=0.065 peak_bytes=2304 token_len=117 err=None\n[127.0.0.1] ok=False time_ms=7.534 peak_bytes=8000983 token_len=2000078 err=InvalidSignatureError\n[127.0.0.1] ok=True time_ms=6.347 peak_bytes=8001061 token_len=2000117 err=None\n\n[127.0.0.1] ok=True time_ms=0.066 peak_bytes=2304 token_len=117 err=None\n[127.0.0.1] ok=False time_ms=23.034 peak_bytes=32000983 token_len=8000078 err=InvalidSignatureError\n[127.0.0.1] ok=True time_ms=22.097 peak_bytes=32001061 token_len=8000117 err=None\n```\n\n**Key takeaways from these results**\n\n* At **8,000,000 chars**, a single invalid-signature request still causes:\n\n * **~23 ms** server work\n * **~32 MB** peak allocations\n * returns **401** (invalid signature) \u2192 attacker does not need key.\n\n---\n\n## PoC # 2 - Localhost network client\n\n**File:** [client_localhost.py](https://github.com/user-attachments/files/26132757/client_localhost.py)\n**Purpose:** generates baseline + (invalid signature) + (valid signature) tokens and sends them over HTTP to localhost server.\n\n### Results (client output)\n\n#### payload-chars = 500,000\n\n```text\n=== BASELINE (valid b64=false token) ===\nHTTP: 200\nclient_wall_ms: 6.3499...\nserver_time_ms: 0.10197...\nserver_peak_bytes: 2624\n\n=== ATTACK (INVALID signature - attacker needs no key) ===\nHTTP: 401\nclient_wall_ms: 4.1010...\nserver_time_ms: 2.01217...\nserver_peak_bytes: 2000983\nerror: InvalidSignatureError\n\n=== ATTACK (VALID signature - accepted path still wastes) ===\nHTTP: 200\nclient_wall_ms: 3.6586...\nserver_time_ms: 1.59092...\nserver_peak_bytes: 2001061\n```\n\n#### payload-chars = 2,000,000\n\n```text\n=== BASELINE ===\nHTTP: 200\nserver_time_ms: 0.06527...\nserver_peak_bytes: 2304\n\n=== ATTACK (INVALID signature) ===\nHTTP: 401\nserver_time_ms: 7.53430...\nserver_peak_bytes: 8000983\n\n=== ATTACK (VALID signature) ===\nHTTP: 200\nserver_time_ms: 6.34682...\nserver_peak_bytes: 8001061\n```\n\n#### payload-chars = 8,000,000\n\n```text\n=== BASELINE ===\nHTTP: 200\nserver_time_ms: 0.06573...\nserver_peak_bytes: 2304\n\n=== ATTACK (INVALID signature) ===\nHTTP: 401\nserver_time_ms: 23.03403...\nserver_peak_bytes: 32000983\n\n=== ATTACK (VALID signature) ===\nHTTP: 200\nserver_time_ms: 22.09702...\nserver_peak_bytes: 32001061\n```\n\n**Why this is strong evidence**\n\n* The server clearly does heavy work **before** rejecting invalid signatures.\n* The \u201cvalid signature\u201d case shows even accepted requests waste resources due to unused payload segment.\n\n---\n\n## PoC # 3 - Localhost flood / burst concurrency\n\n**File:** [flood_localhost.py](https://github.com/user-attachments/files/26132760/flood_localhost.py)\n**Purpose:** sends **N concurrent** invalid-signature requests over HTTP to demonstrate queueing/worker starvation.\n\n### Results (your run: 20 concurrent @ 8,000,000 chars)\n\n```text\ntotal_wall_ms: 1374.5405770000616\n\n(16, 401, 1156.4504789998864, 21.350951999920653, 32000983, \u0027InvalidSignatureError\u0027)\n(19, 401, 1151.2852699997893, 21.208721999755653, 32000983, \u0027InvalidSignatureError\u0027)\n(18, 401, 1102.7211239997996, 21.685218999664357, 32000983, \u0027InvalidSignatureError\u0027)\n(13, 401, 1102.0718189997751, 21.26572200040755, 32000983, \u0027InvalidSignatureError\u0027)\n(11, 401, 1095.9345460000804, 20.586017000368884, 32000983, \u0027InvalidSignatureError\u0027)\n(17, 401, 1085.2552810001725, 22.893039000337012, 32000983, \u0027InvalidSignatureError\u0027)\n(10, 401, 1078.3629560000918, 22.737160999895423, 32000983, \u0027InvalidSignatureError\u0027)\n(7, 401, 1048.2011740000416, 22.476282000297942, 32000983, \u0027InvalidSignatureError\u0027)\n(8, 401, 378.93017700025666, 21.377330999712285, 32000983, \u0027InvalidSignatureError\u0027)\n(1, 401, 281.45106800002395, 21.34223099983501, 32000983, \u0027InvalidSignatureError\u0027)\n```\n\n**Interpretation**\n\n* Each request still costs ~**20\u201323 ms** server processing and **~32 MB** peak allocations.\n* But client-observed latency rises up to **~1.15 seconds** because requests queue behind each other \u2192 clear worker starvation/HoL blocking.\n* All were rejected with **401 InvalidSignatureError** \u2192 still unauthenticated.\n\n---\n\n# Fix \n\n### Goal\n\nPrevent unbounded resource consumption from an attacker-controlled payload segment that is unused in `b64=false` detached flow.\n\n### Minimal change strategy\n\nIn `_load()` (or by refactoring parse order), **do not Base64-decode `payload_segment` until after you know whether `b64=false` applies**.\n\nTwo safe options:\n\n1. **Reject non-empty payload segment when `b64=false`**\n\n * Parse header first\n * If `b64` is false and `payload_segment` is non-empty \u2192 raise `DecodeError` *before* decoding\n * Then verification uses `detached_payload` only\n\n2. **Skip decoding payload segment entirely when `b64=false`**\n\n * Keep payload segment as raw bytes or empty\n * Use detached payload for signing input\n\nThis aligns with the idea that detached payload is the trusted payload input for verification; the compact payload segment should not become a resource amplification vector.\n\n(Implementation context: the current decode order and unconditional `base64url_decode(payload_segment)` are visible in the file and line region around `_load()` and `decode_complete()` ([GitHub][1]).)\n\n---\n\n# Workarounds\n\n* Enforce strict **max token length** at the HTTP boundary (proxy/gateway).\n* Apply rate limiting on verification endpoints.\n* If detached JWS (`b64=false`) is not needed in your app, reject tokens where header includes `\"b64\": false`.",
"id": "GHSA-w7vc-732c-9m39",
"modified": "2026-06-15T19:29:12Z",
"published": "2026-06-15T19:29:12Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-48525"
},
{
"type": "PACKAGE",
"url": "https://github.com/jpadilla/pyjwt"
},
{
"type": "WEB",
"url": "https://github.com/pypa/advisory-database/tree/main/vulns/pyjwt/PYSEC-2026-178.yaml"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
],
"summary": "PyJWT: Unauthenticated DoS via unbounded Base64URL decoding of unused payload segment in b64=false detached JWS"
}
OPENSUSE-SU-2026:11024-1
Vulnerability from csaf_opensuse - Published: 2026-06-13 00:00 - Updated: 2026-06-13 00:00| Product | Identifier | Version | Remediation |
|---|---|---|---|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
| Product | Identifier | Version | Remediation |
|---|---|---|---|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
| Product | Identifier | Version | Remediation |
|---|---|---|---|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
| Product | Identifier | Version | Remediation |
|---|---|---|---|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
| Product | Identifier | Version | Remediation |
|---|---|---|---|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64 | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x | — |
Vendor Fix
|
|
| Unresolved product id: openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64 | — |
Vendor Fix
|
{
"document": {
"aggregate_severity": {
"namespace": "https://www.suse.com/support/security/rating/",
"text": "moderate"
},
"category": "csaf_security_advisory",
"csaf_version": "2.0",
"distribution": {
"text": "Copyright 2024 SUSE LLC. All rights reserved.",
"tlp": {
"label": "WHITE",
"url": "https://www.first.org/tlp/"
}
},
"lang": "en",
"notes": [
{
"category": "summary",
"text": "python311-PyJWT-2.13.0-1.1 on GA media",
"title": "Title of the patch"
},
{
"category": "description",
"text": "These are all security issues fixed in the python311-PyJWT-2.13.0-1.1 package on the GA media of openSUSE Tumbleweed.",
"title": "Description of the patch"
},
{
"category": "details",
"text": "openSUSE-Tumbleweed-2026-11024",
"title": "Patchnames"
},
{
"category": "legal_disclaimer",
"text": "CSAF 2.0 data is provided by SUSE under the Creative Commons License 4.0 with Attribution (CC-BY-4.0).",
"title": "Terms of use"
}
],
"publisher": {
"category": "vendor",
"contact_details": "https://www.suse.com/support/security/contact/",
"name": "SUSE Product Security Team",
"namespace": "https://www.suse.com/"
},
"references": [
{
"category": "external",
"summary": "SUSE ratings",
"url": "https://www.suse.com/support/security/rating/"
},
{
"category": "self",
"summary": "URL of this CSAF notice",
"url": "https://ftp.suse.com/pub/projects/security/csaf/opensuse-su-2026_11024-1.json"
},
{
"category": "self",
"summary": "SUSE CVE CVE-2026-48522 page",
"url": "https://www.suse.com/security/cve/CVE-2026-48522/"
},
{
"category": "self",
"summary": "SUSE CVE CVE-2026-48523 page",
"url": "https://www.suse.com/security/cve/CVE-2026-48523/"
},
{
"category": "self",
"summary": "SUSE CVE CVE-2026-48524 page",
"url": "https://www.suse.com/security/cve/CVE-2026-48524/"
},
{
"category": "self",
"summary": "SUSE CVE CVE-2026-48525 page",
"url": "https://www.suse.com/security/cve/CVE-2026-48525/"
},
{
"category": "self",
"summary": "SUSE CVE CVE-2026-48526 page",
"url": "https://www.suse.com/security/cve/CVE-2026-48526/"
}
],
"title": "python311-PyJWT-2.13.0-1.1 on GA media",
"tracking": {
"current_release_date": "2026-06-13T00:00:00Z",
"generator": {
"date": "2026-06-13T00:00:00Z",
"engine": {
"name": "cve-database.git:bin/generate-csaf.pl",
"version": "1"
}
},
"id": "openSUSE-SU-2026:11024-1",
"initial_release_date": "2026-06-13T00:00:00Z",
"revision_history": [
{
"date": "2026-06-13T00:00:00Z",
"number": "1",
"summary": "Current version"
}
],
"status": "final",
"version": "1"
}
},
"product_tree": {
"branches": [
{
"branches": [
{
"branches": [
{
"category": "product_version",
"name": "python311-PyJWT-2.13.0-1.1.aarch64",
"product": {
"name": "python311-PyJWT-2.13.0-1.1.aarch64",
"product_id": "python311-PyJWT-2.13.0-1.1.aarch64"
}
},
{
"category": "product_version",
"name": "python313-PyJWT-2.13.0-1.1.aarch64",
"product": {
"name": "python313-PyJWT-2.13.0-1.1.aarch64",
"product_id": "python313-PyJWT-2.13.0-1.1.aarch64"
}
},
{
"category": "product_version",
"name": "python314-PyJWT-2.13.0-1.1.aarch64",
"product": {
"name": "python314-PyJWT-2.13.0-1.1.aarch64",
"product_id": "python314-PyJWT-2.13.0-1.1.aarch64"
}
}
],
"category": "architecture",
"name": "aarch64"
},
{
"branches": [
{
"category": "product_version",
"name": "python311-PyJWT-2.13.0-1.1.ppc64le",
"product": {
"name": "python311-PyJWT-2.13.0-1.1.ppc64le",
"product_id": "python311-PyJWT-2.13.0-1.1.ppc64le"
}
},
{
"category": "product_version",
"name": "python313-PyJWT-2.13.0-1.1.ppc64le",
"product": {
"name": "python313-PyJWT-2.13.0-1.1.ppc64le",
"product_id": "python313-PyJWT-2.13.0-1.1.ppc64le"
}
},
{
"category": "product_version",
"name": "python314-PyJWT-2.13.0-1.1.ppc64le",
"product": {
"name": "python314-PyJWT-2.13.0-1.1.ppc64le",
"product_id": "python314-PyJWT-2.13.0-1.1.ppc64le"
}
}
],
"category": "architecture",
"name": "ppc64le"
},
{
"branches": [
{
"category": "product_version",
"name": "python311-PyJWT-2.13.0-1.1.s390x",
"product": {
"name": "python311-PyJWT-2.13.0-1.1.s390x",
"product_id": "python311-PyJWT-2.13.0-1.1.s390x"
}
},
{
"category": "product_version",
"name": "python313-PyJWT-2.13.0-1.1.s390x",
"product": {
"name": "python313-PyJWT-2.13.0-1.1.s390x",
"product_id": "python313-PyJWT-2.13.0-1.1.s390x"
}
},
{
"category": "product_version",
"name": "python314-PyJWT-2.13.0-1.1.s390x",
"product": {
"name": "python314-PyJWT-2.13.0-1.1.s390x",
"product_id": "python314-PyJWT-2.13.0-1.1.s390x"
}
}
],
"category": "architecture",
"name": "s390x"
},
{
"branches": [
{
"category": "product_version",
"name": "python311-PyJWT-2.13.0-1.1.x86_64",
"product": {
"name": "python311-PyJWT-2.13.0-1.1.x86_64",
"product_id": "python311-PyJWT-2.13.0-1.1.x86_64"
}
},
{
"category": "product_version",
"name": "python313-PyJWT-2.13.0-1.1.x86_64",
"product": {
"name": "python313-PyJWT-2.13.0-1.1.x86_64",
"product_id": "python313-PyJWT-2.13.0-1.1.x86_64"
}
},
{
"category": "product_version",
"name": "python314-PyJWT-2.13.0-1.1.x86_64",
"product": {
"name": "python314-PyJWT-2.13.0-1.1.x86_64",
"product_id": "python314-PyJWT-2.13.0-1.1.x86_64"
}
}
],
"category": "architecture",
"name": "x86_64"
},
{
"branches": [
{
"category": "product_name",
"name": "openSUSE Tumbleweed",
"product": {
"name": "openSUSE Tumbleweed",
"product_id": "openSUSE Tumbleweed",
"product_identification_helper": {
"cpe": "cpe:/o:opensuse:tumbleweed"
}
}
}
],
"category": "product_family",
"name": "SUSE Linux Enterprise"
}
],
"category": "vendor",
"name": "SUSE"
}
],
"relationships": [
{
"category": "default_component_of",
"full_product_name": {
"name": "python311-PyJWT-2.13.0-1.1.aarch64 as component of openSUSE Tumbleweed",
"product_id": "openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64"
},
"product_reference": "python311-PyJWT-2.13.0-1.1.aarch64",
"relates_to_product_reference": "openSUSE Tumbleweed"
},
{
"category": "default_component_of",
"full_product_name": {
"name": "python311-PyJWT-2.13.0-1.1.ppc64le as component of openSUSE Tumbleweed",
"product_id": "openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le"
},
"product_reference": "python311-PyJWT-2.13.0-1.1.ppc64le",
"relates_to_product_reference": "openSUSE Tumbleweed"
},
{
"category": "default_component_of",
"full_product_name": {
"name": "python311-PyJWT-2.13.0-1.1.s390x as component of openSUSE Tumbleweed",
"product_id": "openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x"
},
"product_reference": "python311-PyJWT-2.13.0-1.1.s390x",
"relates_to_product_reference": "openSUSE Tumbleweed"
},
{
"category": "default_component_of",
"full_product_name": {
"name": "python311-PyJWT-2.13.0-1.1.x86_64 as component of openSUSE Tumbleweed",
"product_id": "openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64"
},
"product_reference": "python311-PyJWT-2.13.0-1.1.x86_64",
"relates_to_product_reference": "openSUSE Tumbleweed"
},
{
"category": "default_component_of",
"full_product_name": {
"name": "python313-PyJWT-2.13.0-1.1.aarch64 as component of openSUSE Tumbleweed",
"product_id": "openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64"
},
"product_reference": "python313-PyJWT-2.13.0-1.1.aarch64",
"relates_to_product_reference": "openSUSE Tumbleweed"
},
{
"category": "default_component_of",
"full_product_name": {
"name": "python313-PyJWT-2.13.0-1.1.ppc64le as component of openSUSE Tumbleweed",
"product_id": "openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le"
},
"product_reference": "python313-PyJWT-2.13.0-1.1.ppc64le",
"relates_to_product_reference": "openSUSE Tumbleweed"
},
{
"category": "default_component_of",
"full_product_name": {
"name": "python313-PyJWT-2.13.0-1.1.s390x as component of openSUSE Tumbleweed",
"product_id": "openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x"
},
"product_reference": "python313-PyJWT-2.13.0-1.1.s390x",
"relates_to_product_reference": "openSUSE Tumbleweed"
},
{
"category": "default_component_of",
"full_product_name": {
"name": "python313-PyJWT-2.13.0-1.1.x86_64 as component of openSUSE Tumbleweed",
"product_id": "openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64"
},
"product_reference": "python313-PyJWT-2.13.0-1.1.x86_64",
"relates_to_product_reference": "openSUSE Tumbleweed"
},
{
"category": "default_component_of",
"full_product_name": {
"name": "python314-PyJWT-2.13.0-1.1.aarch64 as component of openSUSE Tumbleweed",
"product_id": "openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64"
},
"product_reference": "python314-PyJWT-2.13.0-1.1.aarch64",
"relates_to_product_reference": "openSUSE Tumbleweed"
},
{
"category": "default_component_of",
"full_product_name": {
"name": "python314-PyJWT-2.13.0-1.1.ppc64le as component of openSUSE Tumbleweed",
"product_id": "openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le"
},
"product_reference": "python314-PyJWT-2.13.0-1.1.ppc64le",
"relates_to_product_reference": "openSUSE Tumbleweed"
},
{
"category": "default_component_of",
"full_product_name": {
"name": "python314-PyJWT-2.13.0-1.1.s390x as component of openSUSE Tumbleweed",
"product_id": "openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x"
},
"product_reference": "python314-PyJWT-2.13.0-1.1.s390x",
"relates_to_product_reference": "openSUSE Tumbleweed"
},
{
"category": "default_component_of",
"full_product_name": {
"name": "python314-PyJWT-2.13.0-1.1.x86_64 as component of openSUSE Tumbleweed",
"product_id": "openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
},
"product_reference": "python314-PyJWT-2.13.0-1.1.x86_64",
"relates_to_product_reference": "openSUSE Tumbleweed"
}
]
},
"vulnerabilities": [
{
"cve": "CVE-2026-48522",
"ids": [
{
"system_name": "SUSE CVE Page",
"text": "https://www.suse.com/security/cve/CVE-2026-48522"
}
],
"notes": [
{
"category": "general",
"text": "PyJWT is a JSON Web Token implementation in Python. Prior to 2.13.0, PyJWKClient passes its uri argument directly to urllib.request.urlopen() which uses Python stdlib\u0027s default OpenerDirector registering HTTPHandler, HTTPSHandler, FTPHandler, FileHandler, and DataHandler. There is currently no documented option to restrict which schemes PyJWKClient will fetch. If an application\u0027s jku URL ingestion path accepts attacker-influenced URLs (e.g., from JWT header, configuration file, OAuth flow parameter), the attacker can cause PyJWKClient to read arbitrary local files via file:// (SSRF on local filesystem), cause PyJWKClient to attempt FTP / data-URI fetches (broader SSRF surface), or forge tokens that PyJWT verifies as valid. The library does not directly return non-HTTP(S) URI contents to the attacker; the chained \"plant a JWKS to forge tokens\" scenario described in the original report requires additional application-layer flaws (attacker write access to a filesystem path, untrusted jku derivation) that this fix does not address. This vulnerability is fixed in 2.13.0.",
"title": "CVE description"
}
],
"product_status": {
"recommended": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
},
"references": [
{
"category": "external",
"summary": "CVE-2026-48522",
"url": "https://www.suse.com/security/cve/CVE-2026-48522"
},
{
"category": "external",
"summary": "SUSE Bug 1266798 for CVE-2026-48522",
"url": "https://bugzilla.suse.com/1266798"
}
],
"remediations": [
{
"category": "vendor_fix",
"details": "To install this SUSE Security Update use the SUSE recommended installation methods like YaST online_update or \"zypper patch\".\n",
"product_ids": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
}
],
"scores": [
{
"cvss_v3": {
"baseScore": 4.8,
"baseSeverity": "MEDIUM",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N",
"version": "3.1"
},
"products": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
}
],
"threats": [
{
"category": "impact",
"date": "2026-06-13T00:00:00Z",
"details": "moderate"
}
],
"title": "CVE-2026-48522"
},
{
"cve": "CVE-2026-48523",
"ids": [
{
"system_name": "SUSE CVE Page",
"text": "https://www.suse.com/security/cve/CVE-2026-48523"
}
],
"notes": [
{
"category": "general",
"text": "PyJWT is a JSON Web Token implementation in Python. From 2.9.0 to 2.12.1, there is a verifier-side algorithm allow-list bypass when jwt.decode() or jwt.decode_complete() are called with a PyJWK key. The token header alg is checked against the caller-supplied algorithms allow-list, but signature verification is performed with the algorithm bound to the PyJWK object instead of the header algorithm. An attacker who controls a registered JWK/JWKS private key can sign with a disallowed algorithm, advertise an allowed algorithm in the JWT header, and still be accepted. The issue affects the documented PyJWKClient.get_signing_key_from_jwt(...) flow. This vulnerability is fixed in 2.13.0.",
"title": "CVE description"
}
],
"product_status": {
"recommended": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
},
"references": [
{
"category": "external",
"summary": "CVE-2026-48523",
"url": "https://www.suse.com/security/cve/CVE-2026-48523"
},
{
"category": "external",
"summary": "SUSE Bug 1266799 for CVE-2026-48523",
"url": "https://bugzilla.suse.com/1266799"
}
],
"remediations": [
{
"category": "vendor_fix",
"details": "To install this SUSE Security Update use the SUSE recommended installation methods like YaST online_update or \"zypper patch\".\n",
"product_ids": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
}
],
"scores": [
{
"cvss_v3": {
"baseScore": 5.4,
"baseSeverity": "MEDIUM",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
"version": "3.1"
},
"products": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
}
],
"threats": [
{
"category": "impact",
"date": "2026-06-13T00:00:00Z",
"details": "moderate"
}
],
"title": "CVE-2026-48523"
},
{
"cve": "CVE-2026-48524",
"ids": [
{
"system_name": "SUSE CVE Page",
"text": "https://www.suse.com/security/cve/CVE-2026-48524"
}
],
"notes": [
{
"category": "general",
"text": "PyJWT is a JSON Web Token implementation in Python. Prior to 2.13.0, PyJWKClient.get_signing_key() forces a fresh HTTP request to the JWKS endpoint for every JWT with an unknown kid value, with no rate limiting. Since kid comes from the unverified token header, an attacker can trigger unlimited outbound requests. The vulnerability surfaces only when a JWKS fetch fails; an attacker can attempt to provoke that with sustained unknown-kid traffic, but the outcome depends on upstream JWKS-endpoint behavior (rate limiting, transient errors) which is beyond the attacker\u0027s control. This vulnerability is fixed in 2.13.0.",
"title": "CVE description"
}
],
"product_status": {
"recommended": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
},
"references": [
{
"category": "external",
"summary": "CVE-2026-48524",
"url": "https://www.suse.com/security/cve/CVE-2026-48524"
},
{
"category": "external",
"summary": "SUSE Bug 1266800 for CVE-2026-48524",
"url": "https://bugzilla.suse.com/1266800"
}
],
"remediations": [
{
"category": "vendor_fix",
"details": "To install this SUSE Security Update use the SUSE recommended installation methods like YaST online_update or \"zypper patch\".\n",
"product_ids": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
}
],
"scores": [
{
"cvss_v3": {
"baseScore": 3.7,
"baseSeverity": "LOW",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L",
"version": "3.1"
},
"products": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
}
],
"threats": [
{
"category": "impact",
"date": "2026-06-13T00:00:00Z",
"details": "low"
}
],
"title": "CVE-2026-48524"
},
{
"cve": "CVE-2026-48525",
"ids": [
{
"system_name": "SUSE CVE Page",
"text": "https://www.suse.com/security/cve/CVE-2026-48525"
}
],
"notes": [
{
"category": "general",
"text": "PyJWT is a JSON Web Token implementation in Python. From 2.8.0 to 2.12.1, when verifying detached JWS tokens using the unencoded-payload option (\"b64\": false, RFC 7797), PyJWT performs Base64URL decoding of the compact-serialization payload segment before enforcing the detached-payload rules. For b64=false, PyJWT later discards that decoded payload and replaces it with the caller-provided detached_payload. In practice, this turns the middle segment into an attacker-controlled \u201cwork amplifier\u201d: a remote client can supply an arbitrarily large Base64URL payload segment that forces CPU work + memory allocations even if the signature is invalid. This creates an unauthenticated DoS vector against any endpoint that verifies detached JWS using PyJWT. This vulnerability is fixed in 2.13.0.",
"title": "CVE description"
}
],
"product_status": {
"recommended": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
},
"references": [
{
"category": "external",
"summary": "CVE-2026-48525",
"url": "https://www.suse.com/security/cve/CVE-2026-48525"
},
{
"category": "external",
"summary": "SUSE Bug 1266801 for CVE-2026-48525",
"url": "https://bugzilla.suse.com/1266801"
}
],
"remediations": [
{
"category": "vendor_fix",
"details": "To install this SUSE Security Update use the SUSE recommended installation methods like YaST online_update or \"zypper patch\".\n",
"product_ids": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
}
],
"scores": [
{
"cvss_v3": {
"baseScore": 7.5,
"baseSeverity": "HIGH",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"version": "3.1"
},
"products": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
}
],
"threats": [
{
"category": "impact",
"date": "2026-06-13T00:00:00Z",
"details": "important"
}
],
"title": "CVE-2026-48525"
},
{
"cve": "CVE-2026-48526",
"ids": [
{
"system_name": "SUSE CVE Page",
"text": "https://www.suse.com/security/cve/CVE-2026-48526"
}
],
"notes": [
{
"category": "general",
"text": "PyJWT is a JSON Web Token implementation in Python. Prior to 2.13.0, when the verifier is decoding JSON Web Tokens, while supporting both asymmetric and HMAC algorithms, the library does not validate use of JSON Web Keys in HMAC algorithm, allowing attacker to use the issuer public key as the secret key for HMAC algorithm. This vulnerability is fixed in 2.13.0.",
"title": "CVE description"
}
],
"product_status": {
"recommended": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
},
"references": [
{
"category": "external",
"summary": "CVE-2026-48526",
"url": "https://www.suse.com/security/cve/CVE-2026-48526"
},
{
"category": "external",
"summary": "SUSE Bug 1266802 for CVE-2026-48526",
"url": "https://bugzilla.suse.com/1266802"
}
],
"remediations": [
{
"category": "vendor_fix",
"details": "To install this SUSE Security Update use the SUSE recommended installation methods like YaST online_update or \"zypper patch\".\n",
"product_ids": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
}
],
"scores": [
{
"cvss_v3": {
"baseScore": 7.4,
"baseSeverity": "HIGH",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N",
"version": "3.1"
},
"products": [
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python311-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python313-PyJWT-2.13.0-1.1.x86_64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.aarch64",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.ppc64le",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.s390x",
"openSUSE Tumbleweed:python314-PyJWT-2.13.0-1.1.x86_64"
]
}
],
"threats": [
{
"category": "impact",
"date": "2026-06-13T00:00:00Z",
"details": "important"
}
],
"title": "CVE-2026-48526"
}
]
}
PYSEC-2026-178
Vulnerability from pysec - Published: 2026-05-28 16:16 - Updated: 2026-06-02 10:34PyJWT is a JSON Web Token implementation in Python. From 2.8.0 to 2.12.1, when verifying detached JWS tokens using the unencoded-payload option ("b64": false, RFC 7797), PyJWT performs Base64URL decoding of the compact-serialization payload segment before enforcing the detached-payload rules. For b64=false, PyJWT later discards that decoded payload and replaces it with the caller-provided detached_payload. In practice, this turns the middle segment into an attacker-controlled “work amplifier”: a remote client can supply an arbitrarily large Base64URL payload segment that forces CPU work + memory allocations even if the signature is invalid. This creates an unauthenticated DoS vector against any endpoint that verifies detached JWS using PyJWT. This vulnerability is fixed in 2.13.0.
| Name | purl | pyjwt | pkg:pypi/pyjwt |
|---|
{
"affected": [
{
"ecosystem_specific": {},
"package": {
"ecosystem": "PyPI",
"name": "pyjwt",
"purl": "pkg:pypi/pyjwt"
},
"ranges": [
{
"events": [
{
"introduced": "2.8.0"
},
{
"fixed": "2.13.0"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"2.10.0",
"2.10.1",
"2.11.0",
"2.12.0",
"2.12.1",
"2.8.0",
"2.9.0"
]
}
],
"aliases": [
"CVE-2026-48525",
"GHSA-w7vc-732c-9m39"
],
"details": "PyJWT is a JSON Web Token implementation in Python. From 2.8.0 to 2.12.1, when verifying detached JWS tokens using the unencoded-payload option (\"b64\": false, RFC 7797), PyJWT performs Base64URL decoding of the compact-serialization payload segment before enforcing the detached-payload rules. For b64=false, PyJWT later discards that decoded payload and replaces it with the caller-provided detached_payload. In practice, this turns the middle segment into an attacker-controlled \u201cwork amplifier\u201d: a remote client can supply an arbitrarily large Base64URL payload segment that forces CPU work + memory allocations even if the signature is invalid. This creates an unauthenticated DoS vector against any endpoint that verifies detached JWS using PyJWT. This vulnerability is fixed in 2.13.0.",
"id": "PYSEC-2026-178",
"modified": "2026-06-02T10:34:21.164106Z",
"published": "2026-05-28T16:16:29.533Z",
"references": [
{
"type": "EVIDENCE",
"url": "https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39"
}
],
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
]
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.