CVE-2026-103001 in PyJWT
Summary
by MITRE • 10/01/2026
PyJWT is a Python implementation of JSON Web Token standards. From 2.11.0 through 2.13.0, PyJWT's PyJWT._merge_options() method can modify a caller-supplied mutable options mapping when verify_signature is false. If an application reuses that same mapping for a later decode() or decode_complete() call and changes verify_signature to true, the mapping can retain false values for expiration, not-before, issued-at, audience, issuer, subject, and JWT ID checks. A signed token with invalid registered claims can then be accepted without disabling signature verification, but applications that create a fresh options mapping for each call are not affected.
Be aware that VulDB is the high quality source for vulnerability data.
Analysis
by VulDB Data Team • 10/01/2026
The vulnerability identified in PyJWT versions 2.11.0 through 2.13.0 represents a critical logic flaw within the library's token validation mechanism, specifically affecting how configuration states persist across multiple operations when mutable data structures are reused. PyJWT is widely adopted as the standard Python implementation for creating and verifying JSON Web Tokens, which are essential for stateless authentication and authorization in modern web applications. The core of this issue lies in the internal _merge_options() method, which is responsible for combining user-supplied options with default settings before processing a token. When an application invokes decode or decode_complete methods to verify a JWT, it typically passes a dictionary containing verification parameters such as whether signature validation should occur and what claims must be validated.
The technical flaw arises when the caller supplies a mutable Python dictionary as the options mapping and sets the verify_signature parameter to false during an initial decoding operation. In this scenario, PyJWT modifies the provided dictionary in place to reflect the decision not to perform cryptographic verification or claim checks. Specifically, it may set flags related to expiration, not-before, issued-at, audience, issuer, subject, and JWT ID validation to states that effectively disable these security controls. Because Python dictionaries are mutable objects passed by reference rather than copy, this modification persists in the original object outside the scope of the function call. This behavior violates the principle of least surprise for developers who expect configuration parameters to remain isolated per operation unless explicitly intended otherwise.
The operational impact becomes severe when an application reuses that same options dictionary for a subsequent decode or decode_complete call where verify_signature is set back to true, intending to enforce strict security checks. Due to the prior in-place modification, the internal state of the options mapping retains the disabled flags from the previous unverified operation. Consequently, even though signature verification is technically enabled by setting verify_signature to true, the specific claim validation logic remains bypassed because the underlying configuration dictionary still indicates that expiration and other registered claims should not be checked. This allows an attacker to present a signed JWT with invalid or expired claims, such as an expired timestamp or mismatched audience, which would normally be rejected, but is instead accepted by the application due to the lingering state corruption from the previous call.
This vulnerability aligns closely with CWE-672, Use of Outside-Controlled Variable, and CWE-1035, Incorrect State Transition, as it involves improper handling of mutable external data that affects subsequent security decisions. It also maps to MITRE ATT&CK techniques related to Token Manipulation, specifically the ability to bypass validation controls through state confusion or resource mismanagement. The risk is particularly high in applications that optimize performance by reusing configuration objects across multiple requests rather than instantiating fresh mappings for each token verification process. Such optimization patterns are common in high-throughput microservices and API gateways where object allocation overhead is a concern, making this flaw potentially exploitable at scale against vulnerable deployments.
Mitigation strategies must address both the immediate code defect and broader architectural practices regarding configuration management. The primary remediation involves upgrading to PyJWT version 2.13.1 or later, where developers have corrected the in-place mutation behavior by ensuring that options are copied before modification, thereby isolating each verification operation's state from previous calls. For applications unable to upgrade immediately due to dependency constraints, a defensive coding pattern should be implemented wherein new option dictionaries are created for every decode or decode_complete invocation rather than reusing existing ones. This ensures that no residual configuration data from prior unverified operations can influence subsequent security checks. Additionally, developers should audit their codebase for any shared mutable state passed into PyJWT methods and refactor those instances to use immutable configurations or fresh dictionary literals per request cycle to eliminate the possibility of cross-call contamination.