GHSA-833g-cqhp-h72j File Browser: Share API exposes the password hash and bypass token
SummaryWhen 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`)**`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`)**An admin calling `GET /api/shares` receives the bcrypt hash and bypass token for all shares across all users.PoCTested against `filebrowser/filebrowser:v2.63.15`.**Attack Vector: read the bcrypt hash and bypass token from the share API:**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`: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 `token` is 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/shares` as 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 FixNever serialize the hash or the bypass token to clients. Change the JSON tags so the secrets stay server-side:`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.
CVSS v3.1 score: 2.7