CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2025-68158

Authlib's Amnesia: How a Cache Lookup Flaw Led to 1-Click Account Takeover

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 23, 2026·6 min read·27 visits

Executive Summary (TL;DR)

Authlib < 1.6.6 failed to bind OAuth 'state' data to user sessions when using server-side caching (e.g., Redis). Attackers could generate a valid state, send the callback URL to a victim, and hijack the account via Login CSRF.

OAuth is a complex beast, and the `state` parameter is its primary defense against Cross-Site Request Forgery (CSRF). In Authlib versions prior to 1.6.6, a critical logic error occurred when developers opted for performance by storing OAuth states in a backend cache (like Redis or Memcached) instead of cookies. The library failed to cryptographically bind the cached state to the user's browser session. This decoupling allowed attackers to generate a valid OAuth flow, harvest the URL, and trick a victim into consuming it—effectively performing a Login CSRF or account linking attack with a single click.

The Hook: When Performance Kills Security

If you build Python web applications, you probably use Authlib. It is the Swiss Army knife of OAuth and OpenID Connect, powering authentication for thousands of Flask, Django, and Starlette apps. It abstracts away the misery of the OAuth 2.0 handshake, handling the redirect dances and token exchanges so you don't have to.

The cornerstone of OAuth security is the state parameter. It is a random token generated by the client (your app) to prevent CSRF. It says, "I am the one who started this request, and I am the one finishing it." Without it, anyone could force your browser to log in to their account, or worse, link their rogue Google account to your administrative profile.

Here is the twist: Authlib handled this perfectly fine in its default mode (storing state in cookies). But developers love speed. We love scaling. So, we switch the storage backend to Redis or Memcached to keep our cookies small. In Authlib versions before 1.6.6, flipping that switch was like locking your front door but leaving the keys taped to the outside of the window. The library stopped checking who owned the state, and only checked if the state existed.

The Flaw: The Valet Parking Problem

To understand this bug, imagine a valet parking service. Normally, you hand over your keys and get a ticket (the state). When you return, you show your ticket, and the valet checks two things: 1) Is this a valid ticket? and 2) Does the face matching this ticket look like the guy who dropped off the car?

Authlib's cache-backed implementation skipped step 2.

In framework_integration.py, the logic for retrieving state data looked something like this (simplified):

# The Vulnerable Logic
def get_state_data(self, session, state):
    key = f"_state_{self.name}_{state}"
    if self.cache:
        # LOOKUP ONLY BY KEY
        value = self.cache.get(key)
        return value

Do you see the issue? The get_state_data function takes a session object, but it ignores it if a cache is configured. It constructs a lookup key based entirely on the state parameter found in the URL.

This means the state was no longer a secret bound to the user's browser session. It became a global, floating token. If I, the attacker, start a login flow, Authlib writes _state_google_XYZ123 to Redis. If I then send you a link containing state=XYZ123, Authlib looks up that key in Redis, finds it, and says, "Looks legit! Proceed."

The Code: The Smoking Gun

The fix, introduced in commit 2808378611dd6fb2532b189a9087877d8f0c0489, reveals exactly how the maintainers patched the hole. They implemented a "double-binding" strategy. Even if the heavy data lives in Redis, a reference must exist in the user's session cookie.

Here is the critical diff:

  def get_state_data(self, session, state):
      key = f'_state_{self.name}_{state}'
+     # VERIFY THE SESSION HAS THIS KEY
+     if not session.get(key):
+         return None
+
      if self.cache:
          return self.cache.get(key)

Before the patch, the code blindly trusted the cache. After the patch, the code first checks session.get(key). If the user's browser doesn't have the specific cookie indicating they started this flow, the server returns None, and the attack fails. It forces the state to exist in both the shared cache (Redis) and the private session (Cookie).

The Exploit: 1-Click Account Takeover

Let's weaponize this. We are going to perform a classic Login CSRF attack. The goal is to force the victim to log in using the attacker's credentials, or to link the attacker's social profile to the victim's existing account.

The Setup:

  1. Attacker goes to target-app.com/login/google.
  2. Target App generates state=EVIL_STATE, stores it in Redis, and redirects the Attacker to Google.
  3. Attacker captures the URL but pauses. They do not complete the login yet. They now have a valid state sitting in the Target App's Redis cache.

The Trap: 4. Attacker constructs the callback URL: https://target-app.com/authorize?code=ATTACKER_CODE&state=EVIL_STATE. 5. Attacker sends this link to the Victim via email/chat.

The Execution: 6. Victim clicks the link. 7. Target App receives the request. It extracts state=EVIL_STATE. 8. Vulnerable Logic checks Redis for _state_google_EVIL_STATE. It exists! (Because the attacker put it there). 9. Target App logs the user in.

The Payoff: If the application supports "Social Account Linking," and the victim was already logged in, the attacker's Google account is now linked to the victim's profile. The attacker can now log in as the victim at any time using their own Google credentials.

The Impact: Why We Should Panic

While NVD rates this as a Medium (5.7) because it requires user interaction, the practical impact is often Critical. Identity is the perimeter. If I can compromise your identity layer, I don't need an RCE.

In scenarios where this vulnerability is used for Account Linking, the impact is persistent Account Takeover (ATO). The attacker gains a permanent backdoor into the user's account without changing the password.

In Login CSRF scenarios (where the victim is logged in as the attacker), the impact is subtle but dangerous. The victim might upload sensitive documents or credit card details, thinking they are in their own account, effectively handing that data directly to the attacker. For SaaS platforms handling sensitive data, this is a privacy nightmare.

The Fix: Binding the Ghost

The remediation is straightforward: Update Authlib to version 1.6.6 or higher.

If you cannot update immediately, you must modify your FrameworkIntegration or custom OAuth client setup. You need to ensure that whatever storage backend you use, you are cross-referencing the state with the user's current session.

> [!NOTE] > If you are using FileStorage or SQLAlchemy storage for states, check if your implementation relies on FrameworkIntegration. The vulnerability specifically affects the default logic where cache is passed to the registry.

After patching, ensure you rotate all active sessions. The patch changes how states are validated, so pending OAuth flows might fail immediately after deployment (a small price to pay for security).

Official Patches

AuthlibGitHub Commit Diff

Fix Analysis (1)

Technical Appendix

CVSS Score
5.7/ 10
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N
EPSS Probability
0.02%
Top 95% most exploited

Affected Systems

Flask applications using Authlib with CacheDjango applications using Authlib with CacheStarlette/FastAPI applications using Authlib with Cache

Affected Versions Detail

Product
Affected Versions
Fixed Version
Authlib
Authlib
< 1.6.61.6.6
AttributeDetail
Vulnerability TypeCWE-352: Cross-Site Request Forgery (CSRF)
Attack VectorNetwork (Pre-generated State)
CVSS v3.15.7 (Medium)
ImpactAccount Takeover / Account Linking
Fixed Version1.6.6
Affected Componentauthlib.integrations.base_client.framework_integration

MITRE ATT&CK Mapping

T1189Drive-by Compromise
Initial Access
T1550.001Application Access Token
Use Alternative Authentication Material
CWE-352
Cross-Site Request Forgery (CSRF)

The application does not verify that the OAuth state parameter is bound to the user's current session, allowing CSRF attacks.

Known Exploits & Detection

ManualThe advisory describes the Login CSRF flow in detail.
NucleiDetection Template Available

Vulnerability Timeline

Patch Committed (v1.6.6)
2025-12-12
CVE Published
2026-01-08

References & Sources

  • [1]GHSA Advisory
  • [2]NVD Entry

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 12 hours ago•CVE-2025-6965
7.7

CVE-2025-6965: Remote Code Execution via Integer Truncation in SQLite Aggregate Parser

An integer truncation vulnerability (CWE-197) exists in SQLite before version 3.50.2 during the processing of aggregate queries with more than 32,767 distinct column references. This causes an internal 32-bit counter to truncate to a signed 16-bit integer, producing negative values that cause out-of-bounds heap operations in release builds.

Amit Schendel
Amit Schendel
9 views•6 min read
•1 day ago•CVE-2026-47291
9.8

CVE-2026-47291: Remote Code Execution in Windows HTTP.sys Kernel Driver

An integer overflow vulnerability in the Windows kernel-mode HTTP driver (HTTP.sys) allows an unauthenticated remote attacker to execute arbitrary code with kernel privileges or cause a Denial of Service via a specially crafted sequence of HTTP request headers.

Amit Schendel
Amit Schendel
15 views•8 min read
•1 day ago•CVE-2026-11822
7.8

CVE-2026-11822: Memory Corruption and Buffer Overflow in SQLite FTS5 Extension

A memory corruption vulnerability exists in the FTS5 (Full-Text Search 5) extension of SQLite prior to version 3.53.2. An attacker can construct a malicious database file containing corrupt FTS5 page data. Querying this database triggers out-of-bounds reads and heap-based buffer overflows, potentially causing a crash or arbitrary code execution.

Amit Schendel
Amit Schendel
7 views•5 min read
•1 day ago•CVE-2026-56350
6.3

CVE-2026-56350: SSO Enforcement Bypass in n8n via API Parameter Pollution / Mass Assignment

A mass assignment vulnerability (CWE-915) in n8n's self-service settings API endpoint (PATCH /me/settings) allows authenticated Single Sign-On (SSO) users to disable SSO enforcement for their accounts by injecting administrative parameters. This bypasses organizational identity provider controls and multi-factor authentication (MFA).

Amit Schendel
Amit Schendel
8 views•6 min read
•5 days ago•CVE-2026-55699
6.5

CVE-2026-55699: Arbitrary Directory Deletion via Path Traversal in pnpm globalBinDir Resolver

CVE-2026-55699 (also identified as GHSA-4gxm-v5v7-fqc4) is a critical path traversal and arbitrary directory deletion vulnerability in the pnpm package manager. The issue exists because the manifest validation process fails to prevent relative path segments within the package 'bin' keys. When a malicious package containing structured path traversal markers is globally installed and later manipulated, pnpm resolves the target paths through path.join() and passes the resolved paths to a recursive deletion function, resulting in arbitrary directory removal.

Amit Schendel
Amit Schendel
23 views•6 min read
•5 days ago•CVE-2026-55700
7.1

CVE-2026-55700: Path Traversal and Arbitrary File Write in pnpm stage download

A path traversal vulnerability in pnpm stage download allows malicious registries or compromised package manifests to overwrite arbitrary files on the victim's filesystem via unvalidated package name and version fields.

Alon Barad
Alon Barad
16 views•4 min read