VYPR
Moderate severityNVD Advisory· Published Jun 30, 2025· Updated Aug 4, 2025

File Browser Insecurely Handles Passwords

CVE-2025-52997

Description

File Browser provides a file managing interface within a specified directory and it can be used to upload, delete, preview, rename and edit files. Prior to version 2.34.1, a missing password policy and brute-force protection makes the authentication process insecure. Attackers could mount a brute-force attack to retrieve the passwords of all accounts in a given instance. This issue has been patched in version 2.34.1.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/filebrowser/filebrowser/v2Go
< 2.34.12.34.1
github.com/filebrowser/filebrowserGo
<= 1.11.0

Affected products

1

Patches

1
bf37f88c3222

fix: passthrough the minimum password length (#5236)

https://github.com/filebrowser/filebrowserHenrique DiasJun 29, 2025via ghsa
11 files changed · +100065 30
  • auth/hook.go+2 2 modified
    @@ -150,7 +150,7 @@ func (a *HookAuth) SaveUser() (*users.User, error) {
     	}
     
     	if u == nil {
    -		pass, err := users.HashAndValidatePwd(a.Cred.Password, a.Settings.MinimumPasswordLength)
    +		pass, err := users.ValidateAndHashPwd(a.Cred.Password, a.Settings.MinimumPasswordLength)
     		if err != nil {
     			return nil, err
     		}
    @@ -186,7 +186,7 @@ func (a *HookAuth) SaveUser() (*users.User, error) {
     
     		// update the password when it doesn't match the current
     		if p {
    -			pass, err := users.HashAndValidatePwd(a.Cred.Password, a.Settings.MinimumPasswordLength)
    +			pass, err := users.ValidateAndHashPwd(a.Cred.Password, a.Settings.MinimumPasswordLength)
     			if err != nil {
     				return nil, err
     			}
    
  • auth/proxy.go+1 1 modified
    @@ -35,7 +35,7 @@ func (a ProxyAuth) createUser(usr users.Store, setting *settings.Settings, srv *
     	}
     
     	var hashedRandomPassword string
    -	hashedRandomPassword, err = users.HashAndValidatePwd(pwd, setting.MinimumPasswordLength)
    +	hashedRandomPassword, err = users.ValidateAndHashPwd(pwd, setting.MinimumPasswordLength)
     	if err != nil {
     		return nil, err
     	}
    
  • cmd/root.go+1 1 modified
    @@ -432,7 +432,7 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
     
     		log.Println("Randomly generated password for user 'admin':", pwd)
     
    -		password, err = users.HashAndValidatePwd(pwd, set.MinimumPasswordLength)
    +		password, err = users.ValidateAndHashPwd(pwd, set.MinimumPasswordLength)
     		checkErr(err)
     	}
     
    
  • cmd/users_add.go+1 1 modified
    @@ -21,7 +21,7 @@ var usersAddCmd = &cobra.Command{
     		checkErr(err)
     		getUserDefaults(cmd.Flags(), &s.Defaults, false)
     
    -		password, err := users.HashAndValidatePwd(args[1], s.MinimumPasswordLength)
    +		password, err := users.ValidateAndHashPwd(args[1], s.MinimumPasswordLength)
     		checkErr(err)
     
     		user := &users.User{
    
  • cmd/users_update.go+1 1 modified
    @@ -66,7 +66,7 @@ options you want to change.`,
     		}
     
     		if password != "" {
    -			user.Password, err = users.HashAndValidatePwd(password, s.MinimumPasswordLength)
    +			user.Password, err = users.ValidateAndHashPwd(password, s.MinimumPasswordLength)
     			checkErr(err)
     		}
     
    
  • errors/errors.go+13 2 modified
    @@ -1,13 +1,16 @@
     package errors
     
    -import "errors"
    +import (
    +	"errors"
    +	"fmt"
    +)
     
     var (
     	ErrEmptyKey             = errors.New("empty key")
     	ErrExist                = errors.New("the resource already exists")
     	ErrNotExist             = errors.New("the resource does not exist")
     	ErrEmptyPassword        = errors.New("password is empty")
    -	ErrShortPassword        = errors.New("password is too short")
    +	ErrEasyPassword         = errors.New("password is too easy")
     	ErrEmptyUsername        = errors.New("username is empty")
     	ErrEmptyRequest         = errors.New("empty request")
     	ErrScopeIsRelative      = errors.New("scope is a relative path")
    @@ -20,3 +23,11 @@ var (
     	ErrSourceIsParent       = errors.New("source is parent")
     	ErrRootUserDeletion     = errors.New("user with id 1 can't be deleted")
     )
    +
    +type ErrShortPassword struct {
    +	MinimumLength uint
    +}
    +
    +func (e ErrShortPassword) Error() string {
    +	return fmt.Sprintf("password is too short, minimum length is %d", e.MinimumLength)
    +}
    
  • http/auth.go+2 2 modified
    @@ -151,9 +151,9 @@ var signupHandler = func(_ http.ResponseWriter, r *http.Request, d *data) (int,
     
     	d.settings.Defaults.Apply(user)
     
    -	pwd, err := users.HashAndValidatePwd(info.Password, d.settings.MinimumPasswordLength)
    +	pwd, err := users.ValidateAndHashPwd(info.Password, d.settings.MinimumPasswordLength)
     	if err != nil {
    -		return http.StatusInternalServerError, err
    +		return http.StatusBadRequest, err
     	}
     
     	user.Password = pwd
    
  • http/users.go+11 17 modified
    @@ -125,13 +125,9 @@ var userPostHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *
     		return http.StatusBadRequest, fbErrors.ErrEmptyPassword
     	}
     
    -	if len(req.Data.Password) < int(d.settings.MinimumPasswordLength) {
    -		return http.StatusBadRequest, fbErrors.ErrShortPassword
    -	}
    -
    -	req.Data.Password, err = users.HashAndValidatePwd(req.Data.Password, d.settings.MinimumPasswordLength)
    +	req.Data.Password, err = users.ValidateAndHashPwd(req.Data.Password, d.settings.MinimumPasswordLength)
     	if err != nil {
    -		return http.StatusInternalServerError, err
    +		return http.StatusBadRequest, err
     	}
     
     	userHome, err := d.settings.MakeUserDir(req.Data.Username, req.Data.Scope, d.server.Root)
    @@ -167,17 +163,19 @@ var userPutHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request
     		}
     
     		if req.Data.Password != "" {
    -			req.Data.Password, err = users.HashAndValidatePwd(req.Data.Password, d.settings.MinimumPasswordLength)
    +			req.Data.Password, err = users.ValidateAndHashPwd(req.Data.Password, d.settings.MinimumPasswordLength)
    +			if err != nil {
    +				return http.StatusBadRequest, err
    +			}
     		} else {
     			var suser *users.User
     			suser, err = d.store.Users.Get(d.server.Root, d.raw.(uint))
    +			if err != nil {
    +				return http.StatusInternalServerError, err
    +			}
     			req.Data.Password = suser.Password
     		}
     
    -		if err != nil {
    -			return http.StatusInternalServerError, err
    -		}
    -
     		req.Which = []string{}
     	}
     
    @@ -190,13 +188,9 @@ var userPutHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request
     				return http.StatusForbidden, nil
     			}
     
    -			if len(req.Data.Password) < int(d.settings.MinimumPasswordLength) {
    -				return http.StatusBadRequest, fbErrors.ErrShortPassword
    -			}
    -
    -			req.Data.Password, err = users.HashAndValidatePwd(req.Data.Password, d.settings.MinimumPasswordLength)
    +			req.Data.Password, err = users.ValidateAndHashPwd(req.Data.Password, d.settings.MinimumPasswordLength)
     			if err != nil {
    -				return http.StatusInternalServerError, err
    +				return http.StatusBadRequest, err
     			}
     		}
     
    
  • users/assets/common-passwords.txt+100000 0 added
  • users/assets.go+26 0 added
    @@ -0,0 +1,26 @@
    +package users
    +
    +import (
    +	"embed"
    +	"strings"
    +)
    +
    +//go:embed assets
    +var assets embed.FS
    +var commonPasswords map[string]struct{}
    +
    +//nolint:gochecknoinits
    +func init() {
    +	// Password list sourced from:
    +	// https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/100k-most-used-passwords-NCSC.txt
    +	data, err := assets.ReadFile("assets/common-passwords.txt")
    +	if err != nil {
    +		panic(err)
    +	}
    +
    +	passwords := strings.Split(strings.TrimSpace(string(data)), "\n")
    +	commonPasswords = make(map[string]struct{}, len(passwords))
    +	for _, password := range passwords {
    +		commonPasswords[strings.TrimSpace(password)] = struct{}{}
    +	}
    +}
    
  • users/password.go+7 3 modified
    @@ -9,10 +9,14 @@ import (
     	fbErrors "github.com/filebrowser/filebrowser/v2/errors"
     )
     
    -// HashPwd hashes a password.
    -func HashAndValidatePwd(password string, minimumLength uint) (string, error) {
    +// ValidateAndHashPwd validates and hashes a password.
    +func ValidateAndHashPwd(password string, minimumLength uint) (string, error) {
     	if uint(len(password)) < minimumLength {
    -		return "", fbErrors.ErrShortPassword
    +		return "", fbErrors.ErrShortPassword{MinimumLength: minimumLength}
    +	}
    +
    +	if _, ok := commonPasswords[password]; ok {
    +		return "", fbErrors.ErrEasyPassword
     	}
     
     	return HashPwd(password)
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.