Feb 10, 2026·6 min read·7 visits
A case-sensitivity flaw in File Browser's user update logic allows attackers to bypass the 'current password' requirement when changing credentials. By sending 'Password' (Title Case) instead of 'password' (lowercase) in the API request, the security check is skipped, but the password update still succeeds. Fixed in version 2.57.1.
File Browser, the beloved Swiss Army knife for self-hosted file management, suffered from a classic logic error: it forgot that 'Password' and 'password' are not the same thing in the eyes of a Go map. This vulnerability allows an authenticated user (or an attacker with a hijacked session) to change their password—or potentially others—without knowing the current password, effectively bypassing the application's account takeover protection mechanism. It's a textbook example of how a single capital letter can dismantle an entire security check.
In the world of web application security, the mechanism for changing a password is sacred ground. Standard procedure dictates that if you want to change your lock, you must first prove you have the key. This prevents a specific type of chaos: if I walk away from my laptop and leave my session open, a prankster (or adversary) shouldn't be able to lock me out of my own account by changing my password. They should hit a wall asking for the current password.
File Browser, a widely used Go-based file manager, implemented this logic. They had a list of "sensible" (sensitive) fields. If you tried to touch the password, the permissions, or the username, the gatekeeper would stop you and demand proof of ownership (the current password). It's a sound design pattern.
But here is the catch: computers are pedantic. To a human, password, Password, and PASSWORD convey the same concept. To a Go map lookup, they are three entirely different keys. CVE-2026-25889 is the story of how attackers can whisper "Password" with a capital P to walk right past the bouncer, change the locks, and take over the house.
The vulnerability hides in the userPutHandler within http/users.go. When a PUT request arrives to update a user, the application receives a JSON payload containing a list of fields the client wishes to modify. This list is stored in req.Which.
The application maintains a map called sensibleFields. This map acts as a blocklist for sensitive operations. The logic is simple: iterate through the fields the user wants to change, check if they exist in the sensibleFields map, and if they do, trigger the CheckPwd function to verify the current password.
Here is the fatal flaw: Go maps are case-sensitive. The keys in sensibleFields were stored as lowercase strings (e.g., "password"). If the incoming request specifies that it wants to update "Password" (Title Case), the map lookup sensibleFields["Password"] returns false. The application assumes the field is innocuous and skips the security check entirely.
However, the subsequent logic that actually binds the request data to the user struct and updates the database is significantly more lenient (likely due to the behavior of the JSON unmarshaler or struct tags). It happily recognizes "Password" as mapping to the User.Password struct field. The result? The check fails (allowing the request), but the update succeeds (changing the password).
Let's look at the code that caused the issue. It's a brilliant example of how a tiny assumption can lead to a CVE.
The Vulnerable Code (Before Patch):
// http/users.go
// We iterate over the fields the user wants to update
for _, field := range req.Which {
// DIRECT LOOKUP: If the exact string isn't in the map, we skip the check.
if _, ok := sensibleFields[field]; ok {
// This block only runs if 'field' matches a key exactly (e.g., "password")
if !users.CheckPwd(req.CurrentPassword, d.user.Password) {
return http.StatusBadRequest, fberrors.ErrCurrentPasswordIncorrect
}
}
}If field is "Password", ok is false. The code execution flows right past the CheckPwd block.
The Fix (Commit ff2f004):
The fix is incredibly simple: normalize the input. By forcing the field name to lowercase before checking the map, the developers ensure that "Password", "PASSWORD", and "password" all trigger the security check.
// http/users.go
import "strings"
// ...
for _, field := range req.Which {
// NORMALIZE: Downcase the field before looking it up.
if _, ok := sensibleFields[strings.ToLower(field)]; ok {
if !users.CheckPwd(req.CurrentPassword, d.user.Password) {
return http.StatusBadRequest, fberrors.ErrCurrentPasswordIncorrect
}
}
}It's a one-line change, but it makes the difference between a secure app and an account takeover vulnerability.
Exploiting this is trivial once you have an authenticated session. This could be your own account (to establish persistence if you forgot your password) or a stolen session cookie.
The Setup:
You are logged in as a standard user. You want to change your password to "Pwned!123", but you don't know the current password.
The Attack:
You intercept the PUT request to /api/users/1 (assuming your ID is 1) and modify the JSON body.
Standard Request (Blocked):
{
"which": ["password"],
"password": "Pwned!123"
}Response: 400 Bad Request - "Current password incorrect".
Exploit Request (Bypass):
{
"which": ["Password"],
"password": "Pwned!123"
}Note the capital 'P' in the 'which' array.
The Outcome:
"Password" from req.Which.sensibleFields["Password"]. Result: nil/false.password value (or even Password in the data object) to the user struct.Congratulations, you have just changed the lock without the key.
While this vulnerability requires authentication (CVSS 5.4), do not underestimate it. In an enterprise or homelab environment, "Authentication" is often just one XSS away.
If an attacker manages to hijack a session cookie (perhaps via a separate XSS vulnerability or by sniffing traffic on non-HTTPS connections), they typically have access only for the duration of that session. Standard security practice allows the victim to revoke sessions or simply wait for them to expire.
With CVE-2026-25889, a session hijack becomes a permanent Account Takeover (ATO). The attacker uses the temporary session to change the victim's password. Now, even if the victim realizes something is wrong, they cannot log back in. The attacker owns the account permanently.
Furthermore, if an admin account is compromised, this flaw allows the attacker to change the passwords of other users (if the admin interface uses the same endpoint logic) without needing the admin's current password again, facilitating lateral movement across the file system.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
File Browser filebrowser | < 2.57.1 | 2.57.1 |
| Attribute | Detail |
|---|---|
| CVE ID | CVE-2026-25889 |
| CVSS | 5.4 (Medium) |
| CWE | CWE-178 (Improper Handling of Case Sensitivity) |
| Vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N |
| Attack Vector | Network (API) |
| Patch Commit | ff2f00498cff151e2fb1f5f0b16963bf33c3d6d4 |
The software does not properly handle case sensitivity when processing sensitive information, leading to inconsistent application of security controls.