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-2026-23849

Clockwatching: Weaponizing Milliseconds in File Browser Authentication

Alon Barad
Alon Barad
Software Engineer

Jan 21, 2026·6 min read·52 visits

Executive Summary (TL;DR)

File Browser versions prior to 2.55.0 failed to use constant-time comparison logic during authentication. Because verifying a password with bcrypt takes significantly longer than checking if a user exists in the database, the server responded much faster for invalid users than for valid ones. This discrepancy allows attackers to accurately map out valid accounts on the system.

A classic timing side-channel vulnerability in the popular File Browser application allows unauthenticated attackers to enumerate valid usernames by measuring the server's response time during login attempts.

The Hook: The Ticking Time Bomb

In the world of web application security, we often obsess over the data the server explicitly sends back—error messages, stack traces, or JSON payloads. But sometimes, the most damning information isn't what the server says, but how long it takes to say it.

File Browser is a sleek, Go-based file manager that people love for its speed and simplicity. It’s often used to manage sensitive documents, making it a juicy target. However, in its quest for efficiency, the authentication mechanism leaked information through a classic side-channel: time.

This vulnerability (CVE-2026-23849) is a textbook example of a timing attack. It allows an attacker to ask the server, "Does the user 'admin' exist?" and receive a silent "Yes" simply by watching a stopwatch. It’s the digital equivalent of knocking on a door: if someone walks to the peephole to check who it is, you know someone is home, even if they don't open the door. If the house is empty, the silence is immediate.

The Flaw: A Short-Circuit to Disaster

The root cause lies in a common programming optimization that turns fatal in a security context: the short-circuit logical OR operator (||). Developers are taught to optimize code by failing fast. If a condition is met that invalidates the request, why do more work?

In the vulnerable JSONAuth.Auth function, the code logic was essentially: "If the user lookup fails OR the password check fails, deny access."

Here is the logic in plain English:

  1. Check the database for the username.
  2. If the user is NOT found, stop immediately and return an error.
  3. If the user IS found, proceed to hash the provided password and compare it to the stored hash.

The fatal flaw is step 3. File Browser uses bcrypt for password hashing. Bcrypt is intentionally slow. It uses a work factor (cost) to make brute-forcing hard, typically taking 50ms to 500ms depending on the server CPU. A database lookup for a missing user, on the other hand, takes microseconds—maybe 1ms total.

This creates a massive, measurable time gap.

  • Invalid User: ~1ms response.
  • Valid User: ~50ms+ response.

To a hacker, that 50ms difference is as loud as a siren.

The Code: The Smoking Gun

Let's look at the Go code responsible for this logic. This snippet is from auth/json.go.

The Vulnerable Code

u, err := usr.Get(srv.Root, cred.Username)
// The fatal flaw:
// If err != nil (User not found), the second part is NEVER executed.
if err != nil || !users.CheckPwd(cred.Password, u.Password) {
    return nil, os.ErrPermission
}

Go's runtime executes the left side of || first. If err != nil, the statement evaluates to true, and the block executes immediately. The expensive users.CheckPwd function is skipped entirely.

The Fix (Version 2.55.0)

The patch introduces a concept known as "Constant Time Execution" (or strictly speaking, normalized execution time). The developers realized they must perform a bcrypt hash even if the user doesn't exist.

// Define a dummy hash to burn CPU cycles if the user is missing
const dummyHash = "$2a$10$O4mEMeOL/nit6zqe.WQXauLRbRlzb3IgLHsa26Pf0N/GiU9b.wK1m"
 
func (a JSONAuth) Auth(...) {
    u, err := usr.Get(srv.Root, cred.Username)
 
    // Normalize the data
    hash := dummyHash
    if err == nil {
        hash = u.Password
    }
 
    // ALWAYS perform the expensive check
    // If user is missing, we check against dummyHash.
    // If user exists, we check against real hash.
    match := users.CheckPwd(cred.Password, hash)
 
    if !match || err != nil {
        return nil, os.ErrPermission
    }
    return u, nil
}

By forcing the server to crunch numbers regardless of the username's validity, the response times flatten out. The signal is lost in the noise.

The Exploit: Weaponizing Statistics

Exploiting timing attacks over a network (like the internet) is tricky because of "jitter." Network latency varies. A 50ms spike might just be a router hiccup, not a valid user. To exploit this reliably, we use statistics.

The Attack Strategy

  1. Calibration: The attacker sends 50 requests with random, garbage usernames (e.g., user_xyz123). They measure the average response time and calculate the standard deviation.
  2. Thresholding: A threshold is set, usually Mean + (5 * Standard_Deviation). Anything above this is statistically significant.
  3. Enumeration: The attacker iterates through a wordlist (e.g., admin, root, backup).
  4. Verification: If a request exceeds the threshold, it is flagged as a valid user.

The PoC Logic

A Python script targeting this vulnerability would look something like this:

def measure_response(user):
    start = time.perf_counter()
    requests.post(target, json={"username": user, "password": "x"})
    return time.perf_counter() - start
 
# 1. Calibrate Baseline (Invalid Users)
baseline_times = [measure_response(random_str()) for _ in range(50)]
threshold = mean(baseline_times) + 0.05 # Add 50ms buffer
 
# 2. Attack
for user in wordlist:
    latency = measure_response(user)
    if latency > threshold:
        print(f"[+] VALID USER FOUND: {user} ({latency:.4f}s)")

> [!NOTE] > In a real-world scenario, smart attackers will average multiple requests for the same username to smooth out network jitter, making the detection of valid accounts nearly 100% accurate.

The Impact: Why Should You Care?

You might ask, "So what if they know my username? They still need the password."

True, but in security, knowledge is power. Username enumeration is the precursor to more aggressive attacks.

  1. Focused Brute Force: Instead of trying 1000 passwords against 1000 users (1,000,000 requests), I can find the one valid admin user and try 10,000 passwords against just them. It's quieter and more effective.
  2. Social Engineering: If I know j.smith is a user, I can target John Smith with a specific phishing email regarding his File Browser account.
  3. Default Credentials: Attackers will instantly check valid users against common passwords like password, 123456, or the username itself.

In a system like File Browser, which often sits on the perimeter allowing access to internal files, a compromised account often leads to full data exfiltration or Remote Code Execution (if the user can upload files).

The Fix: Remediation

The fix is straightforward: Update to File Browser v2.55.0.

If you cannot update immediately, you must rely on perimeter defenses:

  1. Rate Limiting: Configure your reverse proxy (Nginx, Traefik, Apache) to aggressively rate-limit the /api/login endpoint. If an attacker can only make 1 request every 5 seconds, the statistical analysis required for a timing attack becomes painfully slow.
  2. Fail2Ban: Implement IP banning for repeated failed login attempts. Since the attacker must generate failed logins to measure the time, they will trip this alarm quickly.
  3. WAF Rules: Block requests that look like automated enumeration tools (checking for User-Agent strings or rapid-fire sequencing).

Official Patches

File BrowserCommit fixing the timing leak

Fix Analysis (1)

Technical Appendix

CVSS Score
5.3/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
EPSS Probability
0.09%
Top 100% most exploited

Affected Systems

File Browser (GitHub: filebrowser/filebrowser)

Affected Versions Detail

Product
Affected Versions
Fixed Version
File Browser
File Browser
< 2.55.02.55.0
AttributeDetail
CWE IDCWE-208
Attack VectorNetwork
CVSS5.3 (Medium)
EPSS Score0.0009
ImpactInformation Disclosure (Username Enumeration)
Exploit StatusPoC Available

MITRE ATT&CK Mapping

T1078Valid Accounts
Defense Evasion
T1087Account Discovery
Discovery
CWE-208
Observable Timing Discrepancy

Observable Timing Discrepancy

Known Exploits & Detection

GitHub Security AdvisoryOriginal advisory containing the timing attack logic

Vulnerability Timeline

Vulnerability Published
2026-01-19
Patch Released (v2.55.0)
2026-01-19

References & Sources

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

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

•44 minutes ago•CVE-2026-115883
6.0

CVE-2026-115883: Cross-Namespace Access via Dot-Delimited Labels in LangGraph Postgres and SQLite Stores

An improper input validation and authorization bypass vulnerability exists in the LangGraph storage layer affecting langgraph, langgraph-checkpoint-postgres, and langgraph-checkpoint-sqlite. Because relational store implementations serialize namespace tuples into dot-delimited strings without validating labels on read, search, delete, and batch operations, an attacker who controls a namespace label can inject periods (.) to traverse namespace boundaries and access, modify, or delete data belonging to other namespaces.

Amit Schendel
Amit Schendel
3 views•9 min read
•about 2 hours ago•CVE-2026-115886
6.5

CVE-2026-115886: Unauthenticated Server-Side Request Forgery and Unsafe Reflection in MLflow Scorer Evaluation Endpoints

CVE-2026-115886 (GHSA-2wqp-q3c6-ccj5) is a Server-Side Request Forgery (SSRF) and Unsafe Reflection vulnerability in MLflow versions 3.12.0rc0 prior to 3.17.0. Unauthenticated REST API endpoints accept serialized third-party scorer JSON payloads that are dynamically deserialized and reflectively instantiated without sanitizing constructor keyword arguments. When optional dependencies such as trulens and trulens-providers-litellm are installed, attackers can inject egress-steering arguments into the scorer payload, forcing the MLflow server to dispatch outbound HTTP requests to arbitrary internal destinations or cloud metadata services.

Alon Barad
Alon Barad
3 views•10 min read
•about 3 hours ago•CVE-2026-113872
7.5

CVE-2026-113872: Unauthenticated Process Crash in Express Multer via Late Busboy Stream Resumption

CVE-2026-113872 (GHSA-q7qp-rjg7-q26m) is a high-severity denial-of-service vulnerability affecting the multer multipart/form-data upload middleware for Node.js and Express in versions 2.0.0 through 2.4.0. When an endpoint is configured to accept multiple files using an asynchronous fileFilter callback, a crafted, truncated multipart HTTP request can trigger an unhandled error event on the underlying busboy stream parser after request teardown has already completed. Because all error listeners are stripped during teardown, Node.js treats the resulting error event as an uncaught exception and immediately terminates the server process.

Amit Schendel
Amit Schendel
5 views•12 min read
•about 4 hours ago•CVE-2026-115897
2.1

CVE-2026-115897: Cross-Site Scripting via Function Body Boundary Bypass in serialize-javascript

CVE-2026-115897 (also tracked as GHSA-m5mm-p8h7-m29v and aliased as CVE-2026-115754) is a Cross-Site Scripting (XSS) vulnerability in the Yahoo serialize-javascript npm package prior to version 7.1.3. The flaw exists in the regular expression used by escapeFunctionBody() to neutralize HTML script closing tags within serialized JavaScript functions. Because function bodies are sanitized in isolation before structural formatting is applied, a function whose string representation terminates directly with the sequence '</script' bypasses the positive lookahead check. When combined with serialization formatting options that introduce whitespace delimiters and a subsequent property that supplies a closing bracket, an attacker can prematurely terminate an enclosing HTML <script> block and inject arbitrary HTML or JavaScript into the rendered document.

Amit Schendel
Amit Schendel
4 views•13 min read
•about 5 hours ago•CVE-2026-109841
5.9

CVE-2026-109841: Subresource Integrity Verification Bypass in Node.js Undici

CVE-2026-109841 is a Subresource Integrity (SRI) verification bypass vulnerability in undici, the official HTTP/1.1 and HTTP/2 client library for Node.js that powers the global fetch() implementation. The flaw stems from improper handling of case sensitivity (CWE-178) when validating cryptographic hash algorithm tokens within SRI metadata. Because undici compared incoming algorithm identifiers against a strictly lowercase set without prior ASCII-lowercase normalization, valid uppercase or mixed-case tokens such as SHA256- or Sha384- were treated as unrecognized algorithms and discarded. Under SRI forward-compatibility rules, discarding all provided tokens results in an empty integrity list, causing undici to fail open and accept tampered HTTP response bodies without cryptographic verification.

Alon Barad
Alon Barad
3 views•9 min read
•about 6 hours ago•CVE-2026-109924
5.9

CVE-2026-109924: Unbounded Memory Allocation in Node.js Undici EventSource Stream Parser

A resource allocation vulnerability (CWE-770) exists in the Server-Sent Events (SSE) parser within the Node.js undici HTTP client library. In affected versions, the EventSourceStream implementation fails to restrict the count of internal Buffer chunk references and accumulated string nodes prior to event dispatch boundaries. A malicious or compromised SSE endpoint can exploit this behavior by streaming fragmented, unterminated lines or continuous sequences of short data fields without empty separator lines, bypassing configured byte-size limits and causing a fatal Out-of-Memory (OOM) crash in the client Node.js process.

Amit Schendel
Amit Schendel
5 views•11 min read