Summary
PyJWT: Non-canonical signature segments enable raw-token revocation bypass
PyJWT 2.13.0 accepts compact JWS signature segments containing characters that
are not in the Base64URL alphabet. Appending !!!! to a valid signature does
not change the decoded signature bytes or authenticated claims, but it changes
the serialized token and its SHA-256 hash. An application that indexes logout
or revocation state by the raw token therefore rejects the logged-out token and
accepts its no-key alternate serialization.
This report separates two issues: permissive compact-JWS decoding is the
library behavior, while using raw serialized JWT text as a security identity is
a dangerous application composition. A jti-indexed control blocks both
representations.
Affected Version
Confirmed with PyJWT 2.13.0 on CPython 3.13. The mutation changes only the
signature segment and requires no signing key.
End-to-End Reproduction
.venv-research/bin/python 06-practical-testing/revocation-bypass-lab.py
The loopback-only lab performs:
- Issue a valid HS256 admin token.
- Access
/protectedsuccessfully. - Log out the canonical token and store
SHA256(raw_token). - Confirm canonical replay returns HTTP 401.
- Append
!!!!to only the signature segment. - Confirm the mutated token has the same verified claims and signature bytes,
a different raw hash, and receives HTTP 200. - Repeat with
jti-indexed revocation and confirm both forms return HTTP 401.
Observed statuses for raw-token revocation were 200 -> logout -> 401 for the
canonical token and 200 for the alternate serialization. The jti control
returned 401 for both replays after logout.
Security Boundaries and Severity
This is not signature forgery: the attacker starts with a valid token and
cannot alter its claims. Impact requires a consumer to bind revocation, replay
state, rate limits, or cache identity to the raw compact string. Under that
composition, an authenticated user can bypass logout or token-specific
revocation without the signing key. Medium is suggested for triage because the
security impact is real but application-dependent.
Maintainer update, 2026-09-09
We reproduced the reported behavior on the verified master commit 8915570: appending !!!! to a valid compact-JWS signature segment is accepted, produces the same decoded signature bytes and claims, and changes the serialized token hash. Existing JWS verification controls pass. The behavior is present in the tested release range represented by tags 2.4.0, 2.8.0, 2.10.1, 2.12.1, and 2.13.0.
The security impact is conditional on an application using the raw serialized token as the identity for logout, revocation, replay, rate-limit, or cache state. Under that composition, an attacker who already holds a valid token can use an alternate serialization after the canonical string is revoked. This is not signature forgery or claim alteration; applications should use a semantic identifier such as jti for token identity.
The report is ready to be accepted as a draft for continued remediation. A narrow fix assessment recommends rejecting non-canonical Base64URL characters and padding in compact-JWS segments. No fix commit or release is claimed yet.
Maintainer update, 2026-09-09
The fix has been rebased onto the current master as e6f48401001609a8f99e71fcaf355fb895d508a8 and is ready to be pushed. Compact-JWS header, payload, and signature segments are now required to use the unpadded Base64URL alphabet and canonical re-encoding; a signature segment containing non-canonical characters such as !!!! is rejected before verification. Valid detached b64=false handling remains supported.
Verification on the rebased fix commit passed 372 tests with 4 intentional cryptography-environment skips; Ruff formatting/lint and git diff --check passed. The compressed-payload regression fixture was updated to valid canonical compact-JWS encoding. No release containing the fix has been published yet, so the patched version remains unset pending release planning.
The advisory remains medium severity and unpublished.
Classification update, 2026-09-10
We completed the advisory classification review. The proposed CVSS 3.1 vector is CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N and the proposed CWE classification is CWE-180. The issue permits alternate non-canonical serializations of an already valid signed token to bypass applications that identify tokens by their raw serialization; it does not forge signatures or alter claims. CWE-180 captures validation/canonicalization ordering.
These metadata changes do not alter the affected range, fix status, or lifecycle state.
Maintainer update, 2026-09-11
The verified fix for this advisory is included in PyJWT 2.14.0, released on 2026-09-11 and available on PyPI. PyJWT 2.14.0 is the first release containing the fix. This advisory is now published with 2.14.0 recorded as the patched version.
Impact
CVE-2026-102269 has a CVSS score of 4.8 (Medium). The vector is network-reachable, no privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (2.14.0); upgrading removes the vulnerable code path.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Already deployed Kodem?
See it in your environmentNew to Kodem? Get a demo →Remediation advice
- Reject signature segments containing characters outside
[A-Za-z0-9_-]. - Reject padding and other non-canonical Base64URL encodings for compact JWS.
- Add regression tests proving malformed signature encodings fail before or
during verification. - Document that applications must use a semantic identifier such as
jti, not
the raw serialized token, for revocation and replay state.
Frequently Asked Questions
- What is CVE-2026-102269? CVE-2026-102269 is a medium-severity security vulnerability in PyJWT (pip), affecting versions <= 2.13.0. It is fixed in 2.14.0.
- How severe is CVE-2026-102269? CVE-2026-102269 has a CVSS score of 4.8 (Medium). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
- Which versions of PyJWT are affected by CVE-2026-102269? PyJWT (pip) versions <= 2.13.0 is affected.
- Is there a fix for CVE-2026-102269? Yes. CVE-2026-102269 is fixed in 2.14.0. Upgrade to this version or later.
- Is CVE-2026-102269 exploitable, and should I be worried? Whether CVE-2026-102269 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether CVE-2026-102269 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix CVE-2026-102269? Upgrade
PyJWTto 2.14.0 or later.