Jul 7, 2026·5 min read·10 visits
Better Auth failed to evict cached sessions from secondary storage (e.g., Redis) when deleting users via admin, anonymous, or SCIM endpoints. Deleted users could continue accessing the system with active cookies for up to 7 days.
A critical session persistence vulnerability exists within the Better Auth framework when configured to use external secondary storage (such as Redis or Cloudflare KV) with default database options. Due to four incomplete user-deletion code paths, active user sessions are not evicted from secondary storage caches during deletion events. As a result, deleted users retain full system access via their pre-existing session cookies until the Session Time-To-Live (TTL) expires.
The Better Auth ecosystem utilizes an abstraction layer to manage user registration, authentication, and session handling. To optimize session verification latency, developers frequently deploy a double-tier storage strategy. In this architecture, relational databases host long-term user records, while memory-efficient 'secondaryStorage' systems (such as Redis or Cloudflare KV) handle active session tokens.
By default, the session.storeSessionInDatabase configuration parameter is set to false. When configured in this manner, session data resides exclusively in secondary memory-based storage. In database-centric configurations, relational foreign-key cascading deletes automatically eliminate active session rows when a parent user row is deleted. However, when sessions reside exclusively in cache tiers, session eviction must be explicitly handled by application-level logic.
This vulnerability stems from a logical discrepancy in four separate user-deletion handlers. While core self-deletion routes safely trigger the required two-stage cleanup sequence, the Admin, Anonymous, and SCIM plugin endpoints execute the database-level user deletion without purging the active session cached inside the secondary storage system. This allows unauthorized API access via orphaned sessions.
The underlying cause is categorized under CWE-613 (Insufficient Session Expiration) and CWE-459 (Incomplete Cleanup). The Better Auth database adapter interface exposes two key operations: internalAdapter.deleteUser(userId) and internalAdapter.deleteSessions(userId). In standard deployment topologies using external Key-Value stores, these endpoints must be chained sequentially during deletion routines.
An investigation of the codebase reveals that four operational endpoints failed to orchestrate this chain. Specifically, the framework invoked the database layer to drop the user record but completely bypassed session revocation inside the cache. Because the external session store lacks transactional integrity with the main database, the session token remains active inside the Redis cache.
When a request containing a stale cookie reaches the authentication middleware, getSessionFromCtx queries the secondary storage via internalAdapter.findSession(token). Because the cached session is not deleted, the validation checks succeed. The framework reconstructs a valid user session context without referencing the primary database, permitting unauthorized read/write access until the cache item reaches its natural expiration (TTL), which defaults to 7 days.
An analysis of the vulnerable code paths demonstrates the implementation gap. In the Admin plugin (packages/better-auth/src/plugins/admin/routes.ts), the removeUser API route executed user deletion directly without clearing active cache entries.
// VULNERABLE IMPLEMENTATION (routes.ts)
const removeUser = createAuthRoute("/admin/remove-user", {
method: "POST",
// ... validation schema
}, async (ctx) => {
const { userId } = ctx.body;
// Missing session eviction step
await ctx.context.internalAdapter.deleteUser(userId);
return ctx.json({ success: true });
});The patched version integrates explicit, blocking session revocation prior to deleting user relational rows. This prevents orphaned session records from residing in secondary memory structures.
// PATCHED IMPLEMENTATION (routes.ts)
const removeUser = createAuthRoute("/admin/remove-user", {
method: "POST",
// ... validation schema
}, async (ctx) => {
const { userId } = ctx.body;
// Explicitly evict cached sessions first to guarantee cleanup
await ctx.context.internalAdapter.deleteSessions(userId);
await ctx.context.internalAdapter.deleteUser(userId);
return ctx.json({ success: true });
});This same programmatic deficiency was present across three other handlers. In @better-auth/scim (routes.ts), the SCIM deprovisioning endpoint DELETE /scim/v2/Users/:userId deleted user profiles but left their enterprise sessions intact. Additionally, within the Anonymous plugin, both the /delete-anonymous-user route and the post-link account hook failed to evict temporary sessions, leaving unauthenticated persistent endpoints exposed.
Exploiting this flaw does not require active technical bypasses or complex payload payloads. Instead, it relies on timing and state discrepancies during standard account deprovisioning sequences. The primary threat scenario involves insider threat actors, compromised accounts, or deprovisioned employees.
To demonstrate this flow, consider an enterprise setting using SCIM synchronization. An identity provider detects a terminated employee and issues an automated SCIM deletion request. The application processes the delete operation successfully, removing the database record. However, because the employee's browser has an active session cookie, the employee can continue to query internal API endpoints. The underlying cached session remains untouched, authorizing access to confidential resources until the session TTL expires.
The security implications of this session persistence vulnerability are significant, especially within enterprise environments. A CVSS v3.1 base score of 3.8 (Low) is assigned primarily due to the privileges required to trigger deletion flows (e.g., an Administrator or Identity Provider). However, the actual impact on confidentiality and integrity can be high depending on the application context.
If a malicious insider is terminated, or if an administrator deletes a compromised user account to contain an ongoing incident, the containment will fail. The attacker will maintain access to operational APIs and database records. The vulnerability also directly undermines compliance standards (such as SOC 2 or ISO 27001) that mandate immediate, absolute termination of logical access upon employee deprovisioning.
The primary resolution is to upgrade all dependencies to the patched version. The maintainers resolved these session lifecycle bugs in the official v1.6.11 release. Security teams should perform immediate package updates across affected microservices.
In scenarios where immediate upgrades are blocked by regression testing pipelines, developers can apply targeted database configuration changes. Setting session.storeSessionInDatabase to true acts as a highly effective workaround. This transfers session states to the primary database, where cascading foreign-key rules enforce session destruction at the schema layer.
Alternatively, custom middleware or wrappers around user-deletion tasks can explicitly invoke session revocation via auth.api.revokeUserSessions prior to calling deletion methods. For the Anonymous plugin, implementing manual token clearing inside the onLinkAccount lifecycle hook prevents leftover credentials from persisting.
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
better-auth Better Auth | >= 0.3.4, < 1.6.11 | 1.6.11 |
@better-auth/scim Better Auth | >= 1.6.0, < 1.6.11 | 1.6.11 |
| Attribute | Detail |
|---|---|
| Vulnerability ID | GHSA-2vg6-77g8-24mp |
| CWE ID | CWE-613, CWE-459, CWE-672 |
| Attack Vector | Network |
| CVSS v3.1 Score | 3.8 (Low) |
| Exploit Status | Conceptual / Logic Defect |
| Remediation Status | Patched in v1.6.11 |
The application does not invalidate the session cache inside secondary storage when the corresponding user account is deleted.
CVE-2026-61539 is a critical remote code execution vulnerability in Xinference, an inference API framework for open-source LLMs. In version 2.5.0 and earlier, model-generated outputs representing Llama3 tool calls are passed directly to Python's built-in eval() function inside the parser components. By manipulating conversational input or injecting instructions, an attacker can influence the LLM to output a Python expression containing malicious system commands, resulting in unauthenticated remote code execution on the host. This vulnerability has been resolved in Xinference version 2.7.0.
An uncontrolled resource consumption vulnerability (CWE-400/CWE-789) exists within the kin-openapi Go library prior to version 0.142.0. The vulnerability occurs during the processing of highly sparse array indexes inside query parameters defined in deepObject style. An unauthenticated remote attacker can exploit this flaw to cause an immediate Out-of-Memory (OOM) crash of the target application.
A critical prototype pollution and sandbox escape vulnerability was discovered in the JSONata query and transformation library before versions 1.8.8 and 2.2.0. By providing a malicious JSONata expression that bypasses ownership checks on object properties, remote attackers can execute arbitrary code in the context of the host Node.js application.
CVE-2026-63135 is a critical stored Cross-Site Scripting (XSS) vulnerability affecting YOURLS (Your Own URL Shortener) versions 1.5.1 up to (but not including) 1.10.4. Unauthenticated remote attackers can inject malicious JavaScript arrays by crafting an HTTP Referer header sent to a short URL redirect. This value is saved in the database logs and executed without context-aware escaping when an administrative user views the corresponding statistics visualization page.
CVE-2026-68508 is a high-severity arbitrary code execution vulnerability in facebookresearch/hydra (hydra-core) prior to version 1.3.4. The vulnerability exists within the dynamic instantiation system hydra.utils.instantiate(), which resolves and executes arbitrary Python callables from configuration files. An attacker capable of submitting untrusted configurations can achieve arbitrary code execution in the context of the consuming process.
A critical sandbox escape vulnerability in JSONata versions prior to 1.8.8 and 2.2.1 allows unauthenticated remote attackers to execute arbitrary code on the host machine. By submitting crafted JSONata expressions, an attacker can manipulate internal AST structures, bypass object clone helpers, spoof native function flags, and escape the evaluation environment to execute system commands through the Node.js runtime.