Skip to content

Commit dbd6de2

Browse files
committed
fixing cwe-338
1 parent d7246f0 commit dbd6de2

File tree

3 files changed

+41
-8
lines changed

3 files changed

+41
-8
lines changed

child/child.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
package child
55

66
import (
7+
"crypto/rand"
78
"errors"
89
"fmt"
910
"io"
1011
"log"
11-
"math/rand"
12+
"math/big"
1213
"os"
1314
"os/exec"
1415
"strings"
@@ -475,7 +476,14 @@ func (c *Child) randomSplay() <-chan time.Time {
475476
}
476477

477478
ns := c.splay.Nanoseconds()
478-
t := time.Duration(rand.Int63n(ns))
479+
// Use crypto/rand for secure random generation (CWE-338 fix)
480+
n, err := rand.Int(rand.Reader, big.NewInt(ns))
481+
if err != nil {
482+
// Fallback to no splay on error
483+
c.logger.Printf("[WARN] (child) failed to generate random splay: %v", err)
484+
return time.After(0)
485+
}
486+
t := time.Duration(n.Int64())
479487

480488
c.logger.Printf("[DEBUG] (child) waiting %.2fs for random splay", t.Seconds())
481489

dependency/vault_common.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
package dependency
55

66
import (
7+
"crypto/rand"
78
"encoding/json"
89
"fmt"
910
"log"
10-
"math/rand"
11+
"math/big"
1112
"sync"
1213
"time"
1314

@@ -185,15 +186,16 @@ func leaseCheckWait(s *Secret, retryCount int) time.Duration {
185186
sleep = sleep / 3.0
186187

187188
// Use some randomness so many clients do not hit Vault simultaneously.
188-
sleep = sleep * (rand.Float64() + 1) / 2.0
189+
randVal := secureRandomFloat64()
190+
sleep = sleep * (randVal + 1) / 2.0
189191
} else if !rotatingSecret {
190192
// If the secret doesn't have a rotation period, this is a non-renewable leased
191193
// secret.
192194
// For non-renewable leases set the renew duration to use much of the secret
193195
// lease as possible. Use a stagger over the configured threshold
194196
// fraction of the lease duration so that many clients do not hit
195197
// Vault simultaneously.
196-
finalFraction := VaultLeaseRenewalThreshold + (rand.Float64()-0.5)*0.1
198+
finalFraction := VaultLeaseRenewalThreshold + (secureRandomFloat64()-0.5)*0.1
197199
if finalFraction >= 1.0 || finalFraction <= 0.0 {
198200
// If the fraction randomly winds up outside of (0.0-1.0), clamp
199201
// back down to the VaultLeaseRenewalThreshold provided by the user,
@@ -208,10 +210,26 @@ func leaseCheckWait(s *Secret, retryCount int) time.Duration {
208210
return time.Duration(sleep)
209211
}
210212

213+
// secureRandomFloat64 returns a cryptographically secure random float64 in [0.0, 1.0)
214+
func secureRandomFloat64() float64 {
215+
// Generate a random 53-bit integer (mantissa precision of float64)
216+
// Use crypto/rand for secure random generation (CWE-338 fix)
217+
218+
max := big.NewInt(1 << 53)
219+
n, err := rand.Int(rand.Reader, max)
220+
if err != nil {
221+
// Fallback to 0.5 on error (middle of range)
222+
log.Printf("[WARN] failed to generate secure random number: %v", err)
223+
return 0.5
224+
}
225+
return float64(n.Int64()) / float64(max.Int64())
226+
}
227+
211228
// jitter adds randomness to a duration to prevent thundering herd.
212229
// It reduces the duration by up to maxJitter (10%) randomly.
213230
func jitter(t time.Duration) time.Duration {
214-
f := float64(t) * (1.0 - maxJitter*rand.Float64())
231+
randVal := secureRandomFloat64()
232+
f := float64(t) * (1.0 - maxJitter*randVal)
215233
return time.Duration(f)
216234
}
217235

watch/view.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
package watch
55

66
import (
7+
"crypto/rand"
78
"errors"
89
"fmt"
910
"log"
10-
"math/rand"
11+
"math/big"
1112
"reflect"
1213
"sync"
1314
"time"
@@ -311,7 +312,13 @@ const minDelayBetweenUpdates = time.Millisecond * 100
311312
func rateLimiter(start time.Time) time.Duration {
312313
remaining := minDelayBetweenUpdates - time.Since(start)
313314
if remaining > 0 {
314-
dither := time.Duration(rand.Int63n(20000000)) // 0-20ms in nanoseconds
315+
// Use crypto/rand for secure random generation (CWE-338 fix)
316+
n, err := rand.Int(rand.Reader, big.NewInt(20000000))
317+
if err != nil {
318+
// Fallback to no dither on error
319+
return remaining
320+
}
321+
dither := time.Duration(n.Int64()) // 0-20ms in nanoseconds
315322
return remaining + dither
316323
}
317324
return 0

0 commit comments

Comments
 (0)