CVE-2026-110861
Executive Summary
CVE-2026-110861 is a race condition (TOCTOU) vulnerability in the database-backed rate limiter of Better Auth, an open-source authentication framework for TypeScript/Node.js applications. In affected releases of the @better-auth/drizzle-adapter and better-auth packages (1.6.17 up to but not including 1.7.7) and the @better-auth/kysely-adapter package (1.6.17 up to but not including 1.7.0), the rate-limit counter check is not performed atomically with the counter update when backed by PostgreSQL. A remote, unauthenticated attacker who issues bursts of concurrent requests can cause multiple requests to pass the limit check simultaneously, exceeding the configured threshold and defeating rate limiting on security-critical endpoints.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Technical Analysis
Better Auth is a self-hosted authentication library used to implement sign-in, session management, two-factor authentication, one-time codes, and password reset flows in Node.js and other JavaScript runtimes. The affected code path is the "database-backed" rate limiter, which stores request counters in a relational database rather than in memory. The advisory scope is explicitly PostgreSQL.
The defect is a classic Time-of-Check to Time-of-Update (TOCTOU) race condition mapped to CWE-307 (Improper Restriction of Excessive Authentication Attempts). The rate limiter performs two logically distinct operations:
- A read/check operation — query the current counter for the relevant key and determine whether the configured limit has been reached.
- A write/update operation — increment the counter and persist it.
Because these two operations are not atomic (no single-statement conditional increment, no row-level locking, no atomic upsert combined with the check), concurrent requests can interleave as follows: multiple requests read the counter while it is still below the limit, all conclude that the request is permitted, and all proceed to increment. The counter ends up above the limit and many more requests than configured are serviced. The NVD description states plainly that "the limit check is not atomic with the counter update." The advisory does not disclose the exact SQL statements, transaction isolation level, or ORM method names used, so those specifics cannot be asserted here.
The critical property of this bug is that rate limiting is a security control, not a performance control. In Better Auth, rate-limited endpoints include password sign-in, two-factor verification, one-time code (OTP) verification, and password reset/account recovery. Each of these endpoints is an oracle, and each is defended primarily by throttling:
- Password sign-in: rate limiting is the primary defense against credential-stuffing and online password guessing.
- Two-factor verification: the 2FA code space is small (typically 6 digits); throttling is what makes online guessing infeasible.
- One-time codes: same small-space brute-force concern.
- Password reset: throttling limits abuse of reset-token or reset-code verification and enumeration.
By collapsing the rate limit, the race condition converts these from "rate-limited oracles" into "effectively unthrottled oracles" for the duration of the concurrent burst. The attacker is not granting themselves authentication directly; they are removing the friction that bounds the number of guesses per unit of time.
The CVSS 3.1 vector CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N (score 3.7) is consistent with this. Network reachable (AV:N), no privileges or user interaction required (PR:N/UI:N), high attack complexity (AC:H) reflecting the timing-sensitive concurrency required, and low confidentiality impact only (C:L) with no integrity or availability impact. The low score reflects the strict precondition that an attacker must win a race and that the ultimate payoff requires a further inference step, not a direct compromise.
Exploitation Scenarios
No public proof-of-concept, Nuclei template, or exploit code is available for this CVE. The chain below is inferred strictly from the vulnerability class (CWE-307 / TOCTOU in a database-backed rate limiter) and the endpoint classes named in the NVD description. No function names, class names, endpoints, or parameters beyond those in the advisory are asserted.
Reconnaissance / target identification. The attacker identifies an application built on Better Auth with the Drizzle or Kysely adapter and PostgreSQL as the backing store, running a vulnerable version (1.6.17 up to 1.7.7 for Drizzle/better-auth core; 1.6.17 up to 1.7.0 for Kysely). Fingerprinting is possible from the presence of the framework's authentication routes and characteristic response behavior (e.g., distinct HTTP responses for sign-in, two-factor, and one-time-code endpoints). No authentication is needed to begin.
Triggering the flaw. The attacker selects a rate-limited endpoint that returns an observable pass/fail oracle — password sign-in (valid vs. invalid credential), two-factor verification (correct vs. incorrect code), one-time code, or password reset verification. Instead of sending guesses sequentially (which would be throttled), the attacker assembles a batch of N candidate guesses and fires them in a single concurrent burst — many parallel connections/requests released at the same instant. Because the limit check and the counter update are not atomic, the concurrent requests all observe the counter below the configured threshold, pass the check together, and are each processed. The per-request guess is still evaluated; the rate limiter simply fails to stop the batch.
Execution method at the vulnerability-class level. The "payload" is concurrency itself: the attacker litters a large number of near-simultaneous requests carrying candidate values (candidate passwords, candidate 2FA/OTP codes, or reset verification values) at the target endpoint. Success is probabilistic and depends on connection parallelism, server concurrency, and timing alignment with the non-atomic read/update window. The attacker may iterate: burst, observe responses, back off briefly, and burst again if any requests are throttled. No memory-corruption payload, file upload, or injection string is involved — this is an abuse of a broken synchronization primitive, not an input-parsing bug.
Post-exploitation impact. The direct effect is that the effective rate limit on the targeted endpoint is breached. If a candidate guess is correct, the attacker obtains the outcome that endpoint grants — an authenticated session (password sign-in), completion of the second authentication factor (2FA verification), consumption of a one-time code, or successful reset verification. Even without a correct guess, the burst reveals throughput information that allows the attacker to tune subsequent attacks. There is no remote code execution, no data exfiltration beyond the oracle's response, and no persistence or lateral movement intrinsic to this vulnerability; the impact is bounded by what the weakened authentication control protects.
Because no exploit code is public, exploitation is expected to be opportunistic and requires the attacker to overcome the engineering challenge of reliably winning the race (AC:H), which is the principal barrier to mass exploitation. Manual and low-volume testing will generally fail to trigger the bug; deliberately high-parallelism tooling is required.
Impact Assessment
Business impact centers on the integrity of authentication assurance rather than confidentiality of arbitrary stored data. CVSS 3.1 scores it 3.7 (Low) with the subscores: AV:N (remotely reachable over the network), AC:H (success depends on winning a timing race under concurrency), PR:N (no authentication required), UI:N (no victim interaction), S:U (impact confined to the vulnerable component), C:L (limited confidentiality impact), I:N (no integrity impact), A:N (no availability impact).
Blast radius. Any deployment of the affected Better Auth versions that (a) uses the Drizzle adapter on a vulnerable core version or the Kysely adapter on a vulnerable version, and (b) relies on the database-backed rate limiter on PostgreSQL, is in scope. Applications using in-memory rate limiting or a non-PostgreSQL database are not described as affected by this advisory. Because Better Auth is typically embedded in self-hosted identity flows, the affected surface is the application's own authentication API, not a multi-tenant SaaS control plane.
Severity considerations that the numeric score understates. The CVSS 3.7 rating reflects the timing/precondition difficulty, not the strategic consequence. Weakening rate limiting on password sign-in enables credential stuffing and online password guessing at an attacker-chosen rate. Weakening it on 2FA/OTP endpoints degrades the second factor to a brute-forceable challenge, which is a meaningful reduction in authentication strength. Password reset endpoints may leak which tokens or codes are valid. For high-value targets, a Low CVSS score should not translate into low remediation priority, because the control being defeated is a security boundary rather than a performance feature. The counter-argument is that the bug does not, by itself, disclose credentials, bypass authentication, or execute code; it removes a defensive layer, and the attacker must still complete a full guessing attack afterward.
Affected versions: Better Auth 1.6.17 before 1.7.7 (core better-auth and @better-auth/drizzle-adapter); @better-auth/kysely-adapter from 1.6.17 before 1.7.0. The OSV entry lists the package path as unfixed at the time of the cited record (0d8b238acc13da34d6769bb413d407b1356703fc → unfixed). No CISA KEV listing; no known exploitation in the wild.
Detection Guidance
Detection for this vulnerability is inherently statistical and behavioral: individual requests look benign, and the signal is a pattern — many near-simultaneous hit/miss events against a rate-limited authentication endpoint within a very short window, with little or no observable throttling. Network and application-layer telemetry (reverse proxy/API gateway logs, Web Application Firewall, and application audit logs) is the primary source. There is no reliable host-based signature because the flaw is a logic/race condition, not malformed input.
Sigma Rule
This rule targets bursts of authentication-related requests from a single source within a short window — the observable effect of a broken rate limiter. Tune thresholds to your normal traffic.
title: Potential Authentication Rate-Limit Bypass via Concurrent Request Burst
id: 8b6b0f4a-3c2f-4d1e-9a77-betterauth-0001
status: experimental
description: Detects high-rate bursts against rate-limited authentication endpoints consistent with a non-atomic, database-backed rate limiter (CVE-2026-110861). Requires tuning.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-110861
author: Threat Intelligence
date: 2024/01/01
logsource:
category: webserver
product: generic
detection:
selection_endpoint:
cs-uri-stem|contains:
- '/sign-in'
- '/two-factor'
- '/one-time-code'
- '/forget-password'
- '/reset-password'
- '/verify'
selection_burst:
sc-status:
- 200
- 401
- 403
- 429
timeframe: 10s
condition: selection_endpoint and selection_burst | count() by src_ip > 40
falsepositives:
- Legitimate load testing
- Shared NAT egress with many users
- Legitimate high-traffic front-ends
level: medium
YARA Rule
No public artifact, payload, or exploit file exists for this CVE; it is a logic flaw, not a file-borne one. This rule is therefore a best-effort, low-confidence heuristic that flags client tooling/config artifacts commonly used to drive concurrent bursts. It is not authoritative and will not detect the vulnerability itself.
rule CVE_2026_110861_BetterAuth_RateLimit_Race_Tooling
{
meta:
description = "Heuristic detection of client-side tooling/config associated with concurrent authentication request bursts against Better Auth rate limiting (CVE-2026-110861). Low confidence."
author = "Threat Intelligence"
date = "2024-01-01"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2026-110861"
severity = "informational"
strings:
$a = "better-auth" ascii nocase
$b = "drizzle-adapter" ascii nocase
$c = "kysely-adapter" ascii nocase
$d = "two-factor" ascii nocase
$e = "one-time-code" ascii nocase
$f1 = "concurrency" ascii nocase
$f2 = "xargs -P" ascii nocase
$f3 = "asyncio.gather" ascii nocase
$f4 = "Promise.all" ascii nocase
condition:
(uint16(0) == 0x213C or uint16(0) == 0x7B7B or true) and
(any of ($a, $b, $c)) and
(any of ($d, $e)) and
(any of ($f*))
}
Suricata IDS Rule
This rule flags an abnormally large volume of authentication-endpoint requests from one source in a short interval, which is the network-visible symptom of a limiter being overwhelmed.
alert http any any -> any any (msg:"CVE-2026-110861 Possible Better Auth Rate-Limit Bypass - High-Rate Auth Endpoint Requests"; flow:established,to_server; http.method; content:"POST"; http.uri; content:"/sign-in"; nocase; threshold: type both, track by_src, count 40, seconds 10; classtype:attempted-user; sid:2026110861; rev:1; metadata:created_at 2024_01_01, reference cve CVE-2026-110861;)
alert http any any -> any any (msg:"CVE-2026-110861 Possible Better Auth Rate-Limit Bypass - Two-Factor/OTP Burst"; flow:established,to_server; http.method; content:"POST"; http.uri; content:"/two-factor"; nocase; threshold: type both, track by_src, count 40, seconds 10; classtype:attempted-user; sid:2026110862; rev:1; metadata:created_at 2024_01_01, reference cve CVE-2026-110861;)
Elastic Detection
This EQL rule fires on a burst of authentication failures from a single host within a short window — the signature of a defeated limiter.
sequence by source.ip with maxspan=10s
[ any where event.category == "web" and
(url.path like "*sign-in*" or url.path like "*two-factor*" or
url.path like "*one-time-code*" or url.path like "*forget-password*" or
url.path like "*reset-password*") and
http.response.status_code in (401, 403, 429, 200) ]
[ any where event.category == "web" and
(url.path like "*sign-in*" or url.path like "*two-factor*" or
url.path like "*one-time-code*" or url.path like "*forget-password*" or
url.path like "*reset-password*") and
http.response.status_code in (401, 403, 429, 200) ]
[ any where event.category == "web" and
(url.path like "*sign-in*" or url.path like "*two-factor*" or
url.path like "*one-time-code*" or url.path like "*forget-password*" or
url.path like "*reset-password*") and
http.response.status_code in (401, 403, 429, 200) ]
Splunk SPL Query
Per-source burst detection on authentication endpoints over a rolling 10-second window.
index=web
(uri_path="*sign-in*" OR uri_path="*two-factor*" OR uri_path="*one-time-code*" OR uri_path="*forget-password*" OR uri_path="*reset-password*")
status IN (200, 401, 403, 429)
| bin _time span=10s
| stats count AS req_count dc(uri_path) AS distinct_paths values(status) AS statuses BY _time, src_ip
| where req_count > 40
| eval cve="CVE-2026-110861", note="Possible Better Auth DB rate-limit race / limiter bypass"
| table _time, src_ip, req_count, distinct_paths, statuses, cve, note
| sort - req_count
Wazuh OSSEC Rule
Correlates repeated authentication failures from the same source to surface limiter-bypass behavior. Adjust frequency and timeframe to match your baseline.
<group name="web,accesslog,better_auth,">
<rule id="100861" level="0">
<if_sid>31100</if_sid>
<url>sign-in|two-factor|one-time-code|forget-password|reset-password</url>
<description>Better Auth protected endpoint access</description>
</rule>
<rule id="100862" level="10" frequency="40" timeframe="10">
<if_matched_sid>100861</if_matched_sid>
<same_source_ip />
<description>CVE-2026-110861 - Possible Better Auth rate-limit bypass: high-frequency auth endpoint requests from same source</description>
<mitre>
<id>T1110</id>
</mitre>
<group>authentication_attack,better_auth,</group>
</rule>
</group>
Mitigation & Patch Guidance
Patch confidence is 2/4: CLAIMED — a single source (OSV) asserts a fix, and it has not been independently confirmed. Treat the version thresholds below as claims to be verified against the vendor's own release notes and changelog before relying on them. No vendor fix reference or official advisory link was provided in the source data, and no workarounds were supplied.
Immediate mitigations (apply now, before or independent of upgrading):
- Enforce rate limiting at a layer that is atomic by construction — a reverse proxy, API gateway, Web Application Firewall, or a distributed limiter (e.g., a token-bucket / sliding-window counter implemented in a shared cache) in front of the application's authentication routes. These external limits are enforced outside the vulnerable database code path and do not suffer the same read-then-write race when implemented correctly.
- Require strong, sufficiently long random secrets for any token-based flows where possible, and reduce reliance on short numeric codes for high-value accounts.
- Enable and centralize audit logging for all authentication endpoints, and alert on the burst patterns described in the Detection Guidance section. Rate limiting alone is no longer trustworthy as a sole control for these endpoints.
- Restrict or monitor egress from hosts toward the authentication API, and block or challenge sources producing abnormal parallel request patterns (bot management / aggregate connection limits).
- If the endpoint mix permits it, shorten session and code lifetimes to reduce the value of any single successful guess.
Patch / upgrade steps:
- Upgrade
@better-auth/drizzle-adapter(and the corebetter-authpackage) to version 1.7.7 or later. - Upgrade
@better-auth/kysely-adapterto version 1.7.0 or later. - Verify the installed version of every Better Auth-related package (core and all adapters) with your package manager; a single stale adapter can retain the vulnerable code path.
- Validate the fix behaviorally after upgrading: replay a controlled concurrent burst against a non-production authentication endpoint and confirm that the configured limit is respected (i.e., excess concurrent requests are rejected) rather than merely observing that an upgrade was performed.
- Because the patch claim is unconfirmed by a second source, confirm against the Better Auth project's release notes/changelog and, if feasible, review the commit that changed the limiter to ensure the check and update are now performed atomically for PostgreSQL.
- Upgrade
Long-term hardening:
- Adopt a consistent rate-limiting architecture across all authentication endpoints and enforce the limit as a single atomic operation (conditional insert-on-conflict, atomic increment with a returned value compared against the threshold, or an equivalent transition). Avoid application-level "read then write" limiters for security controls entirely.
- Make rate limiting a defense-in-depth layer rather than the only barrier: pair it with account lockout/backoff, automation detection, CAPTCHA on repeated failures, IP and device reputation, and notifications on anomalous sign-in patterns.
- Add regression tests that specifically exercise concurrent request bursts against rate-limited endpoints, so that future refactors cannot silently reintroduce a non-atomic check.
- Track Better Auth security advisories and subscribe to release notifications; pin versions and review changelogs for security-relevant changes to authentication and rate-limiting code.
- Periodically reassess prioritization: a Low CVSS score on a broken security control warrants attention proportional to the value of the accounts and second factors it protects, not the raw CVSS number.
References
- NVD — CVE-2026-110861: https://nvd.nist.gov/vuln/detail/CVE-2026-110861
- OSV — vulnerability record and package ranges (cited patch source for this CVE): https://osv.dev/vulnerability/CVE-2026-110861
- Better Auth project documentation and releases (canonical source for the fix; verify patch claims): https://www.better-auth.com
- CWE-307 — Improper Restriction of Excessive Authentication Attempts: https://cwe.mitre.org/data/definitions/307.html
- MITRE ATT&CK T1110 — Brute Force: https://attack.mitre.org/techniques/T1110/
Threat actor campaigns / exploit-in-the-wild: none known. CISA KEV: not listed. EPSS: 0.00217 (approximately the 11.3rd percentile of scored CVEs), indicating a low near-term probability of exploitation. No public PoC, Nuclei template, or exploit code has been observed as of this report.
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.