VYPR
Low severityNVD Advisory· Published Sep 27, 2024· Updated Sep 27, 2024

Dozzle uses unsafe hash for passwords

CVE-2024-47182

Description

Dozzle is a realtime log viewer for docker containers. Before version 8.5.3, the app uses sha-256 as the hash for passwords, which leaves users susceptible to rainbow table attacks. The app switches to bcrypt, a more appropriate hash for passwords, in version 8.5.3.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/amir20/dozzleGo
< 8.5.38.5.3

Affected products

1

Patches

1
de79f03aa3db

feat: uses bcrypt hash instead (#3293)

https://github.com/amir20/dozzleAmir RaminfarSep 26, 2024via ghsa
4 files changed · +37 19
  • docs/guide/authentication.md+10 12 modified
    @@ -18,16 +18,16 @@ The content of the file looks like:
     users:
       # "admin" here is username
       admin:
    -    name: "Admin"
    -    # Just sha-256 which can be computed with "echo -n password | shasum -a 256"
    -    password: "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
         email: me@email.net
    +    name: Admin
    +    # Generate with docker run amir20/dozzle generate --name Admin --email me@email.net --password secret admin
    +    password: $2a$11$9ho4vY2LdJ/WBopFcsAS0uORC0x2vuFHQgT/yBqZyzclhHsoaIkzK
     ```
     
    -> [!TIP]
    -> This file can be generated with `docker run amir20/dozzle generate` with v6.6.x. See [below](#generating-users-yml) for more details.
    +Dozzle uses `email` to generate avatars using [Gravatar](https://gravatar.com/). It is optional. The password is hashed using `bcrypt` which can be generated using `docker run amir20/dozzle generate`.
     
    -Dozzle uses `email` to generate avatars using [Gravatar](https://gravatar.com/). It is optional. The password is hashed using `sha256` which can be generated with `echo -n 'secret-password' | shasum -a 256` or `echo -n 'secret-password' | sha256sum` on linux.
    +> [!WARNING]
    +> In previous versions of Dozzle, SHA-256 was used to hash passwords. Bcrypt is now more secure and is recommended for future use. Dozzle will revert to SHA-256 if it does not find a bcrypt hash. It is advisable to update the password hash to bcrypt using `docker run amir20/dozzle generate`. For more details, see [this issue](https://github.com/amir20/dozzle/security/advisories/GHSA-w7qr-q9fh-fj35).
     
     You will need to mount this file for Dozzle to find it. Here is an example:
     
    @@ -52,21 +52,19 @@ services:
     
     ```yaml [users.yml]
     users:
    -  # "admin" here is username
       admin:
    -    name: "Admin"
    -    # Just sha-256 which can be computed with "echo -n password | shasum -a 256"
    -    password: "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
         email: me@email.net
    +    name: Admin
    +    password: $2a$11$9ho4vY2LdJ/WBopFcsAS0uORC0x2vuFHQgT/yBqZyzclhHsoaIkzK
     ```
     
     :::
     
     Dozzle uses [JWT](https://en.wikipedia.org/wiki/JSON_Web_Token) to generate tokens for authentication. This token is saved in a cookie.
     
    -## Generating users.yml <Badge type="tip" text="v6.6.x" />
    +## Generating users.yml
     
    -Starting with version `v6.6.x`, Dozzle has a builtin `generate` command to generate `users.yml`. Here is an example:
    +Dozzle has a builtin `generate` command to generate `users.yml`. Here is an example:
     
     ```sh
     docker run amir20/dozzle generate admin --password password --email test@email.net --name "John Doe" > users.yml
    
  • go.mod+1 1 modified
    @@ -32,6 +32,7 @@ require (
     	github.com/samber/lo v1.47.0
     	github.com/wk8/go-ordered-map/v2 v2.1.8
     	github.com/yuin/goldmark v1.7.4
    +	golang.org/x/crypto v0.27.0
     	golang.org/x/sync v0.8.0
     	google.golang.org/grpc v1.67.0
     	google.golang.org/protobuf v1.34.2
    @@ -71,7 +72,6 @@ require (
     	go.opentelemetry.io/otel/metric v1.28.0 // indirect
     	go.opentelemetry.io/otel/sdk v1.22.0 // indirect
     	go.opentelemetry.io/otel/trace v1.28.0 // indirect
    -	golang.org/x/crypto v0.27.0 // indirect
     	golang.org/x/text v0.18.0 // indirect
     	google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
     	gotest.tools/v3 v3.0.3 // indirect
    
  • go.sum+0 2 modified
    @@ -29,8 +29,6 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnN
     github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
     github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
     github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
    -github.com/docker/docker v27.3.0+incompatible h1:BNb1QY6o4JdKpqwi9IB+HUYcRRrVN4aGFUTvDmWYK1A=
    -github.com/docker/docker v27.3.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
     github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
     github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
     github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
    
  • internal/auth/users.go+26 4 modified
    @@ -13,6 +13,7 @@ import (
     
     	"github.com/go-chi/jwtauth/v5"
     	"github.com/rs/zerolog/log"
    +	"golang.org/x/crypto/bcrypt"
     	"gopkg.in/yaml.v3"
     )
     
    @@ -61,7 +62,11 @@ func GenerateUsers(user User, hashPassword bool) *bytes.Buffer {
     	buffer := &bytes.Buffer{}
     
     	if hashPassword {
    -		user.Password = sha256sum(user.Password)
    +		hash, err := bcrypt.GenerateFromPassword([]byte(user.Password), 11)
    +		if err != nil {
    +			log.Fatal().Err(err).Msg("Failed to hash password")
    +		}
    +		user.Password = string(hash)
     	}
     
     	users := UserDatabase{
    @@ -93,8 +98,8 @@ func decodeUsersFromFile(path string) (UserDatabase, error) {
     			log.Fatal().Msgf("User %s has an empty password", username)
     		}
     
    -		if len(user.Password) != 64 {
    -			log.Fatal().Str("password", user.Password).Msgf("User %s has an invalid password hash", username)
    +		if !(len(user.Password) == 64 || len(user.Password) == 60) {
    +			log.Fatal().Str("password", user.Password).Str("user", username).Msg("Invalid password for user")
     		}
     
     		if user.Name == "" {
    @@ -146,9 +151,10 @@ func (u *UserDatabase) FindByPassword(username, password string) *User {
     		return nil
     	}
     
    -	if user.Password != sha256sum(password) {
    +	if !CompareHashAndPassword(user.Password, password) {
     		return nil
     	}
    +
     	return user
     }
     
    @@ -157,6 +163,22 @@ func sha256sum(s string) string {
     	return hex.EncodeToString(bytes[:])
     }
     
    +func CompareHashAndPassword(hash, password string) bool {
    +	if len(hash) == 64 {
    +		log.Warn().Msg("Using sha256sum for password comparison. Consider using a more secure hash algorithm to protected against brute-force attacks. See https://github.com/amir20/dozzle/security/advisories/GHSA-w7qr-q9fh-fj35 for more details.")
    +		return hash == sha256sum(password)
    +	}
    +
    +	if len(hash) == 60 {
    +		err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
    +		return err == nil
    +	}
    +
    +	log.Error().Str("hash", hash).Msg("Invalid hash length. Expecting 64 or 60 characters.")
    +
    +	return false
    +}
    +
     func UserFromContext(ctx context.Context) *User {
     	if user, ok := ctx.Value(remoteUser).(User); ok {
     		return &user
    

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

5

News mentions

0

No linked articles in our index yet.