VYPR
Moderate severityNVD Advisory· Published Feb 17, 2024· Updated Sep 5, 2024

CVE-2024-21495

CVE-2024-21495

Description

Versions of the package github.com/greenpau/caddy-security before 1.0.42 are vulnerable to Insecure Randomness due to using an insecure random number generation library which could possibly be predicted via a brute-force search. Attackers could use the potentially predictable nonce value used for authentication purposes in the OAuth flow to conduct OAuth replay attacks. In addition, insecure randomness is used while generating multifactor authentication (MFA) secrets and creating API keys in the database package.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/greenpau/caddy-securityGo
<= 1.0.42

Affected products

1

Patches

1
ecd3725baf26

security: addresses insecure randomness finding

https://github.com/greenpau/go-authcrunchPaul GreenbergDec 2, 2023via ghsa
9 files changed · +71 85
  • internal/tests/random.go+19 5 modified
    @@ -15,8 +15,10 @@
     package tests
     
     import (
    +	"crypto/rand"
     	"github.com/google/uuid"
    -	"math/rand"
    +	"io"
    +	mathrand "math/rand"
     	"strings"
     )
     
    @@ -28,12 +30,24 @@ func NewID() string {
     // NewRandomString returns a random string.
     func NewRandomString(length int) string {
     	chars := []rune("abcdefghijklmnopqrstuvwxyz0123456789")
    +	charsLen := byte(36)
    +
     	if length == 0 {
     		length = 32
     	}
    -	var b strings.Builder
    -	for i := 0; i < length; i++ {
    -		b.WriteRune(chars[rand.Intn(len(chars))])
    +
    +	b := make([]byte, length)
    +	if _, err := io.ReadFull(rand.Reader, b); err != nil {
    +		var sb strings.Builder
    +		for i := 0; i < length; i++ {
    +			sb.WriteRune(chars[mathrand.Intn(len(chars))])
    +		}
    +		return sb.String()
     	}
    -	return b.String()
    +
    +	for i, char := range b {
    +		b[i] = byte(chars[char%charsLen])
    +	}
    +
    +	return string(b)
     }
    
  • Makefile+3 1 modified
    @@ -102,7 +102,9 @@ clean:
     qtest: covdir
     	@echo "Perform quick tests ..."
     	@#time richgo test -v -coverprofile=.coverage/coverage.out internal/tag/*.go
    +	@#time richgo test -v -coverprofile=.coverage/coverage.out internal/testutils/*.go
     	@#time richgo test $(VERBOSE) $(TEST) -coverprofile=.coverage/coverage.out ./pkg/util/data/...
    +	@time richgo test $(VERBOSE) $(TEST) -coverprofile=.coverage/coverage.out ./pkg/util/...
     	@#time richgo test $(VERBOSE) $(TEST) -coverprofile=.coverage/coverage.out -run TestNewConfig ./*.go
     	@#time richgo test $(VERBOSE) $(TEST) -coverprofile=.coverage/coverage.out -run TestNewServer ./*.go
     	@#time richgo test $(VERBOSE) $(TEST) -coverprofile=.coverage/coverage.out ./pkg/registry/...
    @@ -147,7 +149,7 @@ qtest: covdir
     	@#time richgo test $(VERBOSE) $(TEST) -coverprofile=.coverage/coverage.out ./pkg/authproxy/...
     	@#time richgo test $(VERBOSE) $(TEST) -coverprofile=.coverage/coverage.out ./pkg/identity/...
     	@#time richgo test $(VERBOSE) $(TEST) -coverprofile=.coverage/coverage.out ./pkg/authn/backends/...
    -	@time richgo test $(VERBOSE) $(TEST) -coverprofile=.coverage/coverage.out -run NewAPIKey ./pkg/identity/...
    +	@#time richgo test $(VERBOSE) $(TEST) -coverprofile=.coverage/coverage.out -run NewAPIKey ./pkg/identity/...
     	@go tool cover -html=.coverage/coverage.out -o .coverage/coverage.html
     	@#go tool cover -func=.coverage/coverage.out | grep -v "100.0"
     	@go tool cover -func=.coverage/coverage.out
    
  • pkg/identity/api_key.go+2 1 modified
    @@ -17,6 +17,7 @@ package identity
     import (
     	"github.com/greenpau/go-authcrunch/pkg/errors"
     	"github.com/greenpau/go-authcrunch/pkg/requests"
    +	"github.com/greenpau/go-authcrunch/pkg/util"
     	"golang.org/x/crypto/bcrypt"
     	"time"
     )
    @@ -80,7 +81,7 @@ func NewAPIKey(r *requests.Request) (*APIKey, error) {
     	}
     	p := &APIKey{
     		Comment:   r.Key.Comment,
    -		ID:        GetRandomString(40),
    +		ID:        util.GetRandomString(40),
     		Prefix:    r.Key.Prefix,
     		Payload:   r.Key.Payload,
     		Usage:     r.Key.Usage,
    
  • pkg/identity/api_key_test.go+6 5 modified
    @@ -21,6 +21,7 @@ import (
     	"github.com/greenpau/go-authcrunch/internal/tests"
     	"github.com/greenpau/go-authcrunch/pkg/errors"
     	"github.com/greenpau/go-authcrunch/pkg/requests"
    +	"github.com/greenpau/go-authcrunch/pkg/util"
     )
     
     func TestNewAPIKey(t *testing.T) {
    @@ -37,7 +38,7 @@ func TestNewAPIKey(t *testing.T) {
     				Key: requests.Key{
     					Usage:   "api",
     					Comment: "jsmith-api-key",
    -					Payload: GetRandomStringFromRange(54, 72),
    +					Payload: util.GetRandomStringFromRange(54, 72),
     				},
     			},
     			want: map[string]interface{}{
    @@ -53,7 +54,7 @@ func TestNewAPIKey(t *testing.T) {
     					Usage:    "api",
     					Comment:  "jsmith-api-key",
     					Disabled: true,
    -					Payload:  GetRandomStringFromRange(54, 72),
    +					Payload:  util.GetRandomStringFromRange(54, 72),
     				},
     			},
     			want: map[string]interface{}{
    @@ -91,7 +92,7 @@ func TestNewAPIKey(t *testing.T) {
     			req: &requests.Request{
     				Key: requests.Key{
     					Comment:  "jsmith-api-key",
    -					Payload:  GetRandomStringFromRange(54, 72),
    +					Payload:  util.GetRandomStringFromRange(54, 72),
     					Disabled: true,
     				},
     			},
    @@ -104,7 +105,7 @@ func TestNewAPIKey(t *testing.T) {
     				Key: requests.Key{
     					Usage:    "foo",
     					Comment:  "jsmith-api-key",
    -					Payload:  GetRandomStringFromRange(54, 72),
    +					Payload:  util.GetRandomStringFromRange(54, 72),
     					Disabled: true,
     				},
     			},
    @@ -116,7 +117,7 @@ func TestNewAPIKey(t *testing.T) {
     			req: &requests.Request{
     				Key: requests.Key{
     					Usage:    "api",
    -					Payload:  GetRandomStringFromRange(54, 72),
    +					Payload:  util.GetRandomStringFromRange(54, 72),
     					Disabled: true,
     				},
     			},
    
  • pkg/identity/database.go+2 1 modified
    @@ -20,6 +20,7 @@ import (
     	"github.com/greenpau/go-authcrunch/internal/utils"
     	"github.com/greenpau/go-authcrunch/pkg/errors"
     	"github.com/greenpau/go-authcrunch/pkg/requests"
    +	"github.com/greenpau/go-authcrunch/pkg/util"
     	"github.com/greenpau/versioned"
     	"io/ioutil"
     	"os"
    @@ -566,7 +567,7 @@ func (db *Database) AddAPIKey(r *requests.Request) error {
     	if err != nil {
     		return errors.ErrAddAPIKey.WithArgs(r.Key.Usage, err)
     	}
    -	s := GetRandomStringFromRange(72, 96)
    +	s := util.GetRandomStringFromRange(72, 96)
     	failCount := 0
     	for {
     		hk, err := NewPassword(s)
    
  • pkg/identity/mfa_token.go+2 1 modified
    @@ -36,6 +36,7 @@ import (
     
     	"github.com/greenpau/go-authcrunch/pkg/errors"
     	"github.com/greenpau/go-authcrunch/pkg/requests"
    +	"github.com/greenpau/go-authcrunch/pkg/util"
     )
     
     // MfaTokenBundle is a collection of public keys.
    @@ -99,7 +100,7 @@ func (b *MfaTokenBundle) Size() int {
     // NewMfaToken returns an instance of MfaToken.
     func NewMfaToken(req *requests.Request) (*MfaToken, error) {
     	p := &MfaToken{
    -		ID:         GetRandomString(40),
    +		ID:         util.GetRandomString(40),
     		CreatedAt:  time.Now().UTC(),
     		Parameters: make(map[string]string),
     		Flags:      make(map[string]bool),
    
  • pkg/identity/public_key.go+2 1 modified
    @@ -24,6 +24,7 @@ import (
     	"fmt"
     	"github.com/greenpau/go-authcrunch/pkg/errors"
     	"github.com/greenpau/go-authcrunch/pkg/requests"
    +	"github.com/greenpau/go-authcrunch/pkg/util"
     	"golang.org/x/crypto/openpgp"
     	"golang.org/x/crypto/ssh"
     	"strconv"
    @@ -87,7 +88,7 @@ func (b *PublicKeyBundle) Size() int {
     func NewPublicKey(r *requests.Request) (*PublicKey, error) {
     	p := &PublicKey{
     		Comment:   r.Key.Comment,
    -		ID:        GetRandomString(40),
    +		ID:        util.GetRandomString(40),
     		Payload:   r.Key.Payload,
     		Usage:     r.Key.Usage,
     		CreatedAt: time.Now().UTC(),
    
  • pkg/identity/random.go+0 55 removed
    @@ -1,55 +0,0 @@
    -// Copyright 2022 Paul Greenberg greenpau@outlook.com
    -//
    -// Licensed under the Apache License, Version 2.0 (the "License");
    -// you may not use this file except in compliance with the License.
    -// You may obtain a copy of the License at
    -//
    -//     http://www.apache.org/licenses/LICENSE-2.0
    -//
    -// Unless required by applicable law or agreed to in writing, software
    -// distributed under the License is distributed on an "AS IS" BASIS,
    -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    -// See the License for the specific language governing permissions and
    -// limitations under the License.
    -
    -package identity
    -
    -import (
    -	"math/rand"
    -	"time"
    -)
    -
    -const charset = "abcdefghijklmnopqrstuvwxyz" +
    -	"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    -
    -var seed *rand.Rand = rand.New(
    -	rand.NewSource(time.Now().UnixNano()),
    -)
    -
    -func gen(length int, charset string) string {
    -	b := make([]byte, length)
    -	for i := range b {
    -		b[i] = charset[seed.Intn(len(charset))]
    -	}
    -	return string(b)
    -}
    -
    -// GetRandomString returns X character long random string.
    -func GetRandomString(i int) string {
    -	if i < 1 {
    -		i = 40
    -	}
    -	return gen(i, charset)
    -}
    -
    -// GetRandomStringFromRange generates random string of a random length. The
    -// random lenght is bounded by a and b.
    -func GetRandomStringFromRange(a, b int) string {
    -	var i int
    -	if a > b {
    -		i = rand.Intn(a-b) + b
    -	} else {
    -		i = rand.Intn(b-a) + a
    -	}
    -	return gen(i, charset)
    -}
    
  • pkg/util/random.go+35 15 modified
    @@ -15,9 +15,12 @@
     package util
     
     import (
    +	"crypto/rand"
     	"encoding/base32"
    -	"math/rand"
    -	"time"
    +	"io"
    +	//	"math"
    +	"math/big"
    +	mathrand "math/rand"
     	"unicode"
     )
     
    @@ -33,15 +36,32 @@ var charsetTable = &unicode.RangeTable{
     	LatinOffset: 1,
     }
     
    -var seed *rand.Rand = rand.New(
    -	rand.NewSource(time.Now().UnixNano()),
    -)
    +func genRandInt(i int) uint32 {
    +	n, err := rand.Int(rand.Reader, big.NewInt(int64(i)))
    +	if err != nil {
    +		return uint32(mathrand.Intn(i))
    +	}
    +	//if n.Uint64() > math.MaxUint32+1 {
    +	//	return uint32(n.Uint64() & uint32(0xFFFFFFFF))
    +	//}
    +	return uint32(n.Uint64())
    +}
     
    -func gen(length int, charset string) string {
    +func gen(length uint32, charset string) string {
    +	charsetLen := byte(len(charset))
     	b := make([]byte, length)
    -	for i := range b {
    -		b[i] = charset[seed.Intn(len(charset))]
    +	if _, err := io.ReadFull(rand.Reader, b); err != nil {
    +		// for i uint32 := 0; i < length; i++ {
    +		for i := uint32(0); i < length; {
    +			b[i] = charset[mathrand.Intn(len(charset))]
    +		}
    +		return string(b)
     	}
    +
    +	for i, char := range b {
    +		b[i] = byte(charset[char%charsetLen])
    +	}
    +
     	return string(b)
     }
     
    @@ -50,17 +70,17 @@ func GetRandomString(i int) string {
     	if i < 1 {
     		i = 40
     	}
    -	return gen(i, charset)
    +	return gen(uint32(i), charset)
     }
     
     // GetRandomStringFromRange generates random string of a random length. The
     // random lenght is bounded by a and b.
     func GetRandomStringFromRange(a, b int) string {
    -	var i int
    +	var i uint32
     	if a > b {
    -		i = rand.Intn(a-b) + b
    +		i = genRandInt(a-b) + uint32(b)
     	} else {
    -		i = rand.Intn(b-a) + a
    +		i = genRandInt(b-a) + uint32(a)
     	}
     	return gen(i, charset)
     }
    @@ -75,11 +95,11 @@ func GetRandomEncodedStringFromRange(a, b int) string {
     // GetRandomStringFromRangeWithCharset generates random string of a random length. The
     // random lenght is bounded by a and b. The charset is provided.
     func GetRandomStringFromRangeWithCharset(a, b int, cs string) string {
    -	var i int
    +	var i uint32
     	if a > b {
    -		i = rand.Intn(a-b) + b
    +		i = genRandInt(a-b) + uint32(b)
     	} else {
    -		i = rand.Intn(b-a) + a
    +		i = genRandInt(b-a) + uint32(a)
     	}
     	return gen(i, cs)
     }
    

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

8

News mentions

0

No linked articles in our index yet.