CVE-2026-48522
Medium · 4.2CVSS
4.2
EPSS
0.2%
Published
May 28, 2026
CISA due date
—
Cloudanix analysis
Some Python applications may trust unsafe token key locations, allowing attackers to make the application read local files or accept fake login tokens if other weaknesses are present.
- Exploitation
- Requires User Interaction
- Attacker needs
- User Interaction
- Complexity
- High
- Impact
- Data Exposure
- Component
- Library
- Class
- SSRF
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
PyJWT versions before 2.13.0 allow PyJWKClient to pass a caller-supplied URI directly to Python urllib.request.urlopen(), which supports multiple schemes beyond HTTP and HTTPS, including file://, ftp://, and data:. If an application lets an attacker influence the JWKS/JWK URL used for token verification, the attacker can trigger local file reads through file:// paths, cause outbound requests to unexpected protocols, or, when combined with additional application weaknesses such as attacker-controlled JWKS placement or untrusted jku handling, influence JWT verification and potentially forge tokens accepted by the application. The core issue is insufficient scheme restriction in key-fetching logic; exploitability depends heavily on how the application derives or accepts the JWKS URL.
Why it matters to the business
Applications that use vulnerable PyJWT versions and accept attacker-influenced JWKS URLs may expose sensitive local file contents indirectly, make unexpected outbound requests, or accept attacker-controlled authentication tokens in chained scenarios. The CVSS and EPSS values indicate lower immediate internet-wide exploitation likelihood, and it is not listed in CISA KEV, but the impact can still be significant for identity, API, and OAuth/OIDC-integrated services because JWT verification often gates access to sensitive systems. Organizations with many Python services or shared authentication libraries should prioritize inventory and upgrades because a single unsafe token-validation pattern can affect multiple applications.
How an attack unfolds
An attacker first identifies an application endpoint or workflow that verifies JWTs using PyJWT PyJWKClient and allows some part of the JWKS location to be influenced, such as a JWT jku header, OAuth/OIDC parameter, configuration value, tenant metadata, or other externally supplied URL. The attacker then supplies a non-HTTP(S) URI, such as file:///etc/passwd, ftp://attacker-controlled-host/resource, or a data: URI. In vulnerable versions, PyJWKClient passes that URI to urllib without restricting the scheme, so the application attempts to read from the local filesystem or fetch via the specified protocol. Direct disclosure is not guaranteed because PyJWT does not automatically return fetched content to the attacker, but errors, timing, logs, or application behavior may reveal whether local paths or network destinations were accessed. In a more severe chain, if the attacker can cause the application to fetch a JWKS from an attacker-controlled or attacker-writable location and the application trusts unvalidated jku-derived keys, the attacker may sign a JWT with their own key and have the application accept it as valid.
How to fix it
Upgrade PyJWT to version 2.13.0 or later. In addition to the library upgrade, applications should explicitly restrict JWKS/JWK fetch URLs to trusted HTTPS origins only, reject file://, ftp://, data:, and other non-HTTP(S) schemes, and avoid deriving JWKS locations directly from untrusted JWT headers such as jku unless strict allowlisting is enforced. Prefer static, preconfigured issuer-to-JWKS mappings for trusted identity providers. Disable or block outbound traffic from application runtimes to unnecessary protocols and destinations, especially FTP and local metadata or loopback endpoints. Review JWT validation logic to ensure issuer, audience, algorithm, key ID, and allowed JWKS endpoints are all validated according to a trusted configuration.
How to confirm the fix worked
Confirm all Python environments and dependency lockfiles use PyJWT 2.13.0 or later. Search application code for PyJWKClient usage and verify that any URI passed to it is either hardcoded or selected from a trusted allowlist. Test token-validation paths with jku or equivalent JWKS URL inputs using file://, ftp://, data:, http://127.0.0.1/, and unexpected external HTTPS URLs; fixed and properly hardened applications should reject these before attempting a fetch. Review dependency manifests, container images, SBOMs, and deployed virtual environments for older PyJWT versions. Validate egress controls by confirming the application cannot initiate unintended FTP or local-network requests during token verification.
Typical attack path
- Find an application that uses PyJWT PyJWKClient for JWT verification.
- Identify whether the JWKS URL can be influenced through a JWT header, OAuth/OIDC parameter, configuration source, metadata endpoint, or other user-controlled input.
- Submit a token or request containing a non-HTTP(S) JWKS URL such as file://, ftp://, or data:.
- Observe application behavior, errors, timing differences, outbound traffic, or logs to confirm that the URL was processed by the server.
- If possible, chain the behavior with application-specific weaknesses such as attacker-controlled JWKS hosting, writable local paths, or untrusted jku handling.
- Use an attacker-controlled signing key and JWKS to attempt JWT forgery and unauthorized access.
How to detect it
Review application, API gateway, authentication service, reverse proxy, and identity-provider integration logs for JWTs or token-validation requests containing jku, jwks_uri, x5u, or similar key-location fields with non-HTTP(S) schemes. Search for file://, ftp://, and data: values near authentication failures, JWT decode errors, key retrieval errors, or unusual 4xx/5xx responses. Inspect outbound network telemetry, DNS logs, proxy logs, firewall logs, and EDR network events from Python application processes for unexpected FTP connections, requests to attacker-controlled hosts during token verification, or attempts to reach loopback, link-local, private RFC1918 addresses, and cloud metadata endpoints. Review application error logs for urllib or PyJWT exceptions referencing unsupported key data, failed local file reads, or unexpected URL schemes. If exploitation is suspected, preserve relevant JWT samples, request headers, application logs, dependency versions, process command lines, and egress telemetry to determine whether a forged token was accepted or local resources were accessed.
- jku":"file://
- "jku":"ftp://
- "jku":"data:
- jwks_uri=file://
- jwks_uri=ftp://
- jwks_uri=data:
- x5u":"file://
- x5u":"ftp://
- x5u":"data:
- file:///etc/passwd
- file:///proc/self/environ
- file:///proc/self/cmdline
- file:///var/run/secrets/kubernetes.io/serviceaccount/token
- http://169.254.169.254
- http://127.0.0.1
- http://localhost
- urllib.error.URLError
- PyJWKClientError
- PyJWTError
- No such file or directory: '/etc/passwd'
- Connection refused: ftp://
What your security team should do
- Inventory all applications, containers, serverless functions, and shared Python authentication libraries that include PyJWT.
- Upgrade PyJWT to 2.13.0 or later across source manifests, lockfiles, base images, and deployed artifacts.
- Prioritize internet-facing APIs, identity brokers, OAuth/OIDC integrations, and multi-tenant services that process externally supplied JWTs.
- Review code for PyJWKClient and reject any design that trusts JWT-supplied jku or other attacker-controlled JWKS URLs without a strict allowlist.
- Add validation that permits only trusted HTTPS JWKS endpoints and blocks file://, ftp://, data:, loopback, link-local, and private-network destinations unless explicitly required.
- Add egress monitoring and controls for application runtimes to detect unexpected FTP, local metadata, loopback, and internal network access attempts.
- Search historical logs for evidence of non-HTTP(S) JWKS URLs or unusual token-verification failures.
- Add regression tests that submit JWTs with malicious jku values and assert that no outbound or local-file fetch occurs.
The record
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's 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's 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.
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|---|---|---|
| openSUSE:Leap 16.0 | python-PyJWT | 0 | 2.12.1-160000.2.1 |
| openSUSE:Tumbleweed | python-PyJWT | 0 | 2.13.0-1.1 |
Related vulnerabilities
- CVE-2026-48526 PyJWT is a JSON Web Token implementation in Python. Also affects python-PyJWT
- CVE-2026-48525 PyJWT is a JSON Web Token implementation in Python. Also affects python-PyJWT
- CVE-2026-48523 PyJWT is a JSON Web Token implementation in Python. Also affects python-PyJWT
- CVE-2026-48524 PyJWT is a JSON Web Token implementation in Python. Also affects python-PyJWT
- CVE-2026-32597 PyJWT is a JSON Web Token implementation in Python. Also affects python-PyJWT
- CVE-2024-53861 PyJWT Issuer field partial matches allowed Also affects python-PyJWT
- CVE-2026-101907 Axios is a promise-based HTTP client for the browser and Node.js. CWE-441
- CVE-2026-101905 Axios is a promise-based HTTP client for the browser and Node.js. CWE-441