Skip to content

GHSA-75c5-xw7c-p5pm CVE-2024-53861 PYSEC-2026-1814

PyJWT Issuer field partial matches allowed

High PyPI
Severity
0.0 / 10
High · CVSS 4.0
Exploit chance (EPSS)
0.83%
Chance of exploitation in the next 30 days. Higher than 57.62% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-697 Incorrect Comparison
Fix
2.10.1
Upgrade pyjwt to this version or later

Description

Summary

The wrong string if check is run for iss checking, resulting in "acb" being accepted for "_abc_".

Details

This is a bug introduced in version 2.10.0: checking the "iss" claim changed from isinstance(issuer, list) to isinstance(issuer, Sequence).

-        if isinstance(issuer, list):
+        if isinstance(issuer, Sequence):
            if payload["iss"] not in issuer:
                raise InvalidIssuerError("Invalid issuer")
        else:

Since str is a Sequnce, but not a list, in is also used for string comparison. This results in if "abc" not in "__abcd__": being checked instead of if "abc" != "__abc__":.

PoC

Check out the unit tests added here: https://github.com/jpadilla/pyjwt-ghsa-75c5-xw7c-p5pm

        issuer = "urn:expected"

        payload = {"iss": "urn:"}

        token = jwt.encode(payload, "secret")

        # decode() succeeds, even though `"urn:" != "urn:expected". No exception is raised.
        with pytest.raises(InvalidIssuerError):
            jwt.decode(token, "secret", issuer=issuer, algorithms=["HS256"])

Impact

I would say the real world impact is not that high, seeing as the signature still has to match. We should still fix it.

Affected versions

PyPI

PackageVulnerableFixed in
pyjwt
>= 2.10.0, < 2.10.1
2.10.1

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

pyjwt PyPI → 2.10.1

pip
pip install --upgrade "pyjwt>=2.10.1"
poetry
poetry add "pyjwt>=2.10.1"
uv
uv add "pyjwt>=2.10.1"

Severity breakdown

CVSS 4.0 0.0

CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N

Attack vector
Network
Attack complexity
Low
Attack requirements
Present
Privileges required
High
User interaction
None
Confidentiality (vulnerable system)
None
Integrity (vulnerable system)
Low
Availability (vulnerable system)
None
Confidentiality (subsequent systems)
None
Integrity (subsequent systems)
None
Availability (subsequent systems)
None

CVSS 3.1 2.2

CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:N/I:L/A:N

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

Weakness

CWE-697: Incorrect Comparison

The product compares two entities in a security-relevant context, but the comparison is incorrect.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-pxh4-856f-4h89
PyJWT: HS256/384/512 verify accepts empty HMAC key via oct JWK (PyJWK/PyJWKClient) enabling token forgery
High Also affects pyjwt
GHSA-gvp8-978c-rx2q
PyJWT.decode() reintroduces options-dict mutation, enabling silent claim-verification bypass on dict reuse
Medium Also affects pyjwt
GHSA-x33g-cr3x-6449
PyJWT accepts inconsistent OKP x/d JWKs, causing public/private key identity confusion
High Also affects pyjwt
GHSA-w6j9-cwv2-h6wq
PyJWT: Malformed RSA JWK aborts parsing of an entire JWK Set
High Also affects pyjwt
GHSA-w2cx-738m-mc7w
PyJWT accepts public JWK containers as HMAC secrets
High Also affects pyjwt
GHSA-r6x4-923q-g947
PyJWT BOM Bypass
High Also affects pyjwt
GHSA-p4g4-x82p-q773
PyJWT: Public keys in DER form are accepted as HMAC secrets, bypassing the CVE-2022-29217 guard
High Also affects pyjwt
GHSA-jwrc-g2q2-pq5p
PyJWT: ReDoS vulnerability when calling the `is_pem_format` function.
Medium Also affects pyjwt
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor