🧹 chore: Replace math/rand with crypto/rand#3508
Conversation
|
Warning Rate limit exceeded@gaby has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 0 minutes and 44 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
WalkthroughThe random string generation function was updated to use cryptographically secure randomness instead of a pseudo-random approach. Associated constants for the old method were removed. A new subtest was added to ensure generated strings only contain valid characters from the allowed set. Changes
Sequence Diagram(s)sequenceDiagram
participant Caller
participant hooks.go (unsafeRandString)
participant crypto/rand
Caller->>hooks.go (unsafeRandString): Request random string (n)
hooks.go (unsafeRandString)->>crypto/rand: Generate secure random indices
crypto/rand-->>hooks.go (unsafeRandString): Return random indices
hooks.go (unsafeRandString)->>hooks.go (unsafeRandString): Map indices to allowed characters
hooks.go (unsafeRandString)-->>Caller: Return random string or error
Estimated code review effort2 (~20 minutes) Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3508 +/- ##
==========================================
- Coverage 91.10% 90.97% -0.13%
==========================================
Files 112 112
Lines 11262 11271 +9
==========================================
- Hits 10260 10254 -6
- Misses 748 759 +11
- Partials 254 258 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
client/hooks.go (1)
34-40: Address modulo bias in random character selection.The current implementation introduces statistical bias because 256 (byte range) doesn't divide evenly by 62 (character set length). Some characters will be slightly more likely to appear than others.
Consider using rejection sampling for uniform distribution:
func unsafeRandString(n int) string { b := make([]byte, n) - if _, err := rand.Read(b); err != nil { - panic(fmt.Errorf("failed to read random bytes: %w", err)) - } - - for i := 0; i < n; i++ { - b[i] = letterBytes[int(b[i])%len(letterBytes)] - } + + for i := 0; i < n; i++ { + for { + var randomByte [1]byte + if _, err := rand.Read(randomByte[:]); err != nil { + panic(fmt.Errorf("failed to read random bytes: %w", err)) + } + // Reject values that would cause bias + if randomByte[0] < 248 { // 248 = 62 * 4, largest multiple of 62 <= 255 + b[i] = letterBytes[randomByte[0]%62] + break + } + } + } return utils.UnsafeString(b) }Alternatively, if perfect uniformity isn't critical for boundary generation, the current approach is acceptable and much simpler.
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 35-35: client/hooks.go#L35
Added line #L35 was not covered by testsclient/hooks_test.go (1)
46-52: Good test addition for character set validation.The new subtest effectively verifies that all generated characters belong to the expected character set, which is important given the implementation change. The parallel execution is also appropriate.
Consider adding a test for the error handling path to improve coverage:
t.Run("crypto rand error handling", func(t *testing.T) { // This would require mocking crypto/rand.Read to return an error // or testing in an environment where crypto/rand fails // The current panic behavior may be difficult to test directly })Note: The static analysis tool flagged that the panic path (line 35 in hooks.go) lacks test coverage.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
client/hooks.go(2 hunks)client/hooks_test.go(1 hunks)
🧰 Additional context used
🪛 GitHub Check: codecov/patch
client/hooks.go
[warning] 35-35: client/hooks.go#L35
Added line #L35 was not covered by tests
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Compare
- GitHub Check: unit (1.24.x, windows-latest)
- GitHub Check: repeated
🔇 Additional comments (2)
client/hooks.go (2)
4-4: Excellent security improvement!Switching from
math/randtocrypto/randprovides cryptographically secure randomness, which is much better for generating random boundaries and other security-sensitive values.
28-28: Good cleanup of unused constants.Removing the bit manipulation constants simplifies the code since they're no longer needed with the new approach.
There was a problem hiding this comment.
Pull Request Overview
This PR replaces insecure math/rand usage with crypto/rand for generating random strings, updates the helper to return errors, adjusts multipart-boundary logic to handle those errors, and enhances tests to verify character validity.
- Switched
unsafeRandStringimplementation to usecrypto/randand updated its signature to return an error. - Updated multipart boundary generation to handle potential errors from
unsafeRandString. - Adapted tests to expect an error return and added a new test to ensure only allowed characters are used.
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| client/hooks.go | Replaced math/rand logic with crypto/rand, changed unsafeRandString to return an error, and added error handling in multipart boundary setup. |
| client/hooks_test.go | Modified tests to handle the new error return from unsafeRandString and added a character-set validation test. |
Comments suppressed due to low confidence (2)
client/hooks.go:33
- Update this doc comment to describe the function’s behavior, including its parameter (
n), the returned random string, and the possible error condition.
// An error is returned if the random source fails.
client/hooks.go:34
- [nitpick] Since this function now uses a secure source and returns an error, consider renaming
unsafeRandStringto something likesecureRandStringorrandStringfor clarity.
func unsafeRandString(n int) (string, error) {
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
The switch to crypto/rand isn't necessary for generating multipart boundaries, but it's fine. It avoids gosec warnings, adds negligible overhead. The function name is fine—"unsafe" refers to the string conversion, not the randomness. Merge is reasonable unless performance is a concern.
Just needs full test coverage before merging.
I don't think there's an easy way to trigger a failure on reading random bytes, that's why those 2 lines are missing from tests. |
|
@gaby Can you share benchmark results from before and after |
|
The performance hit is too much, from ~10ns/op to ~300ns/op. |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
client/hooks.go (1)
34-46: Excellent security improvement with minor modernization opportunity.The switch to crypto/rand provides cryptographically secure randomness and eliminates potential bias. The pre-computed bound optimization is well-implemented.
Consider modernizing the for loop to address the static analysis hint:
- for i := 0; i < n; i++ { - idx, err := rand.Int(rand.Reader, bound) - if err != nil { - return "", fmt.Errorf("failed to read random index: %w", err) - } - b[i] = letterBytes[idx.Int64()] - } + for i := range n { + idx, err := rand.Int(rand.Reader, bound) + if err != nil { + return "", fmt.Errorf("failed to read random index: %w", err) + } + b[i] = letterBytes[idx.Int64()] + }Note: The significant performance impact (10ns → 300ns per operation) is an acceptable trade-off for the security benefits provided by crypto/rand.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
client/hooks.go(3 hunks)client/hooks_test.go(1 hunks)
🧠 Learnings (2)
📓 Common learnings
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:20-23
Timestamp: 2024-07-01T03:44:03.672Z
Learning: Unit tests for key length enforcement in both `EncryptCookie` and `DecryptCookie` functions have been added to ensure robust validation and prevent potential runtime errors.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:20-23
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Unit tests for key length enforcement in both `EncryptCookie` and `DecryptCookie` functions have been added to ensure robust validation and prevent potential runtime errors.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:51-54
Timestamp: 2024-07-01T03:33:22.283Z
Learning: Unit tests for key length enforcement in `DecryptCookie` have been added to ensure consistency and security in the encryption processes.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:51-54
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Unit tests for key length enforcement in `DecryptCookie` have been added to ensure consistency and security in the encryption processes.
client/hooks.go (1)
Learnt from: ReneWerner87
PR: gofiber/fiber#0
File: :0-0
Timestamp: 2024-12-01T10:28:36.011Z
Learning: Fiber currently supports square bracket notation in form data with 'application/x-www-form-urlencoded' content type, but this feature is not available for multipart form data. The implementation for form-urlencoded is in ctx.go (BodyParser method), while multipart form data handling needs enhancement to support this feature.
🪛 GitHub Check: modernize
client/hooks.go
[failure] 37-37:
for loop can be modernized using range over int
🪛 GitHub Actions: Modernize Lint
client/hooks.go
[error] 37-37: Go code modernization suggestion: for loop can be modernized using range over int.
🚧 Files skipped from review as they are similar to previous changes (1)
- client/hooks_test.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:20-23
Timestamp: 2024-07-01T03:44:03.672Z
Learning: Unit tests for key length enforcement in both `EncryptCookie` and `DecryptCookie` functions have been added to ensure robust validation and prevent potential runtime errors.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:20-23
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Unit tests for key length enforcement in both `EncryptCookie` and `DecryptCookie` functions have been added to ensure robust validation and prevent potential runtime errors.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:51-54
Timestamp: 2024-07-01T03:33:22.283Z
Learning: Unit tests for key length enforcement in `DecryptCookie` have been added to ensure consistency and security in the encryption processes.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:51-54
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Unit tests for key length enforcement in `DecryptCookie` have been added to ensure consistency and security in the encryption processes.
client/hooks.go (1)
Learnt from: ReneWerner87
PR: gofiber/fiber#0
File: :0-0
Timestamp: 2024-12-01T10:28:36.011Z
Learning: Fiber currently supports square bracket notation in form data with 'application/x-www-form-urlencoded' content type, but this feature is not available for multipart form data. The implementation for form-urlencoded is in ctx.go (BodyParser method), while multipart form data handling needs enhancement to support this feature.
🪛 GitHub Check: modernize
client/hooks.go
[failure] 37-37:
for loop can be modernized using range over int
🪛 GitHub Actions: Modernize Lint
client/hooks.go
[error] 37-37: Go code modernization suggestion: for loop can be modernized using range over int.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: unit (1.24.x, macos-latest)
- GitHub Check: unit (1.24.x, macos-13)
- GitHub Check: Compare
- GitHub Check: repeated
- GitHub Check: unit (1.24.x, windows-latest)
🔇 Additional comments (3)
client/hooks.go (3)
4-4: LGTM: Import changes support the crypto/rand migration.The added imports are necessary for the secure random generation implementation.
Also applies to: 7-7
29-29: LGTM: Character set is appropriate for boundary generation.The letterBytes constant provides a good balance of characters for generating multipart boundaries.
127-132: LGTM: Proper error handling for random generation.The error handling correctly propagates failures from the secure random generation and provides clear context about boundary generation failures.
GoFiber’s client uses math/rand for multipart boundaries, similar to the Node.js form-data CVE-2025-7783, making it potentially predictable. Exploitation needs attacker-controlled input and math/rand output observation (e.g., logs, webhooks), which is harder than Node.js due to server-side context. PR to switch to crypto/rand was closed for performance (~10ns to ~300ns) and concerns were dismissed by me at the time. Looking deeper: Risk is low but non-zero; consider crypto/rand and merge. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
client/hooks.go (1)
34-47: Good bias-avoidance implementation, but consider optimizing the reading strategy.The bias-avoidance logic correctly computes the rejection threshold. However, the current approach of reading
nbytes upfront and then re-reading individual bytes could be optimized.Consider reading bytes one at a time to avoid the overhead of re-reading:
func unsafeRandString(n int) (string, error) { L := byte(len(letterBytes)) max := byte(256 - (256 % int(L))) out := make([]byte, n) - buf := make([]byte, n) - - // Read n raw bytes in one shot - if _, err := rand.Read(buf); err != nil { - return "", fmt.Errorf("rand.Read failed: %w", err) - } - for i, b := range buf { - // Reject values ≥ max - for b >= max { - if _, err := rand.Read(buf[i : i+1]); err != nil { - return "", fmt.Errorf("rand.Read failed: %w", err) - } - b = buf[i] - } - out[i] = letterBytes[b%L] + for i := 0; i < n; i++ { + var b byte + for { + if _, err := rand.Read([]byte{b}); err != nil { + return "", fmt.Errorf("rand.Read failed: %w", err) + } + if b < max { + break + } + } + out[i] = letterBytes[b%L] }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
client/hooks.go(3 hunks)
🧠 Learnings (2)
📓 Common learnings
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:20-23
Timestamp: 2024-07-01T03:44:03.672Z
Learning: Unit tests for key length enforcement in both `EncryptCookie` and `DecryptCookie` functions have been added to ensure robust validation and prevent potential runtime errors.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:20-23
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Unit tests for key length enforcement in both `EncryptCookie` and `DecryptCookie` functions have been added to ensure robust validation and prevent potential runtime errors.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:51-54
Timestamp: 2024-07-01T03:33:22.283Z
Learning: Unit tests for key length enforcement in `DecryptCookie` have been added to ensure consistency and security in the encryption processes.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:51-54
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Unit tests for key length enforcement in `DecryptCookie` have been added to ensure consistency and security in the encryption processes.
client/hooks.go (1)
Learnt from: ReneWerner87
PR: gofiber/fiber#0
File: :0-0
Timestamp: 2024-12-01T10:28:36.011Z
Learning: Fiber currently supports square bracket notation in form data with 'application/x-www-form-urlencoded' content type, but this feature is not available for multipart form data. The implementation for form-urlencoded is in ctx.go (BodyParser method), while multipart form data handling needs enhancement to support this feature.
🪛 GitHub Check: unit (1.24.x, macos-13)
client/hooks.go
[failure] 7-7:
"math/big" imported and not used
[failure] 7-7:
"math/big" imported and not used
🪛 GitHub Check: unit (1.24.x, ubuntu-latest)
client/hooks.go
[failure] 7-7:
"math/big" imported and not used
[failure] 7-7:
"math/big" imported and not used
🪛 GitHub Check: modernize
client/hooks.go
[failure] 7-7:
"math/big" imported and not used
[failure] 7-7:
"math/big" imported and not used
🪛 GitHub Check: govulncheck-check
client/hooks.go
[failure] 7-7:
"math/big" imported and not used
🪛 GitHub Actions: Run govulncheck
client/hooks.go
[error] 7-7: Go compiler error: "math/big" imported and not used.
🪛 GitHub Actions: Modernize Lint
client/hooks.go
[error] 7-7: Go compiler error: "math/big" imported and not used
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:20-23
Timestamp: 2024-07-01T03:44:03.672Z
Learning: Unit tests for key length enforcement in both `EncryptCookie` and `DecryptCookie` functions have been added to ensure robust validation and prevent potential runtime errors.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:20-23
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Unit tests for key length enforcement in both `EncryptCookie` and `DecryptCookie` functions have been added to ensure robust validation and prevent potential runtime errors.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:51-54
Timestamp: 2024-07-01T03:33:22.283Z
Learning: Unit tests for key length enforcement in `DecryptCookie` have been added to ensure consistency and security in the encryption processes.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:51-54
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Unit tests for key length enforcement in `DecryptCookie` have been added to ensure consistency and security in the encryption processes.
client/hooks.go (1)
Learnt from: ReneWerner87
PR: gofiber/fiber#0
File: :0-0
Timestamp: 2024-12-01T10:28:36.011Z
Learning: Fiber currently supports square bracket notation in form data with 'application/x-www-form-urlencoded' content type, but this feature is not available for multipart form data. The implementation for form-urlencoded is in ctx.go (BodyParser method), while multipart form data handling needs enhancement to support this feature.
🪛 GitHub Check: unit (1.24.x, macos-13)
client/hooks.go
[failure] 7-7:
"math/big" imported and not used
[failure] 7-7:
"math/big" imported and not used
🪛 GitHub Check: unit (1.24.x, ubuntu-latest)
client/hooks.go
[failure] 7-7:
"math/big" imported and not used
[failure] 7-7:
"math/big" imported and not used
🪛 GitHub Check: modernize
client/hooks.go
[failure] 7-7:
"math/big" imported and not used
[failure] 7-7:
"math/big" imported and not used
🪛 GitHub Check: govulncheck-check
client/hooks.go
[failure] 7-7:
"math/big" imported and not used
🪛 GitHub Actions: Run govulncheck
client/hooks.go
[error] 7-7: Go compiler error: "math/big" imported and not used.
🪛 GitHub Actions: Modernize Lint
client/hooks.go
[error] 7-7: Go compiler error: "math/big" imported and not used
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: repeated
- GitHub Check: Analyse
- GitHub Check: Compare
- GitHub Check: lint
🔇 Additional comments (2)
client/hooks.go (2)
29-29: Good character set choice for boundary generation.The 62-character set (letters + digits) is well-suited for multipart boundaries and facilitates the bias-avoidance logic in the implementation.
142-147: Excellent error handling for the security improvement.The error handling correctly propagates failures from the crypto/rand source with appropriate context. This maintains robustness while gaining the security benefits of cryptographic randomness.
Note: As mentioned in the PR objectives, this change increases latency from ~10ns to ~300ns per operation, but provides cryptographically secure boundaries that address potential security concerns similar to CVE-2025-7783.
Summary
Related #3383