#23671: fix(security): use crypto.randomInt for session slug generation
agents
size: XS
Cluster:
Session Management Enhancements
## Summary
- Problem: Session slug generation uses `Math.random()` which is not cryptographically secure and produces predictable output
- Why it matters: Session slugs serve as identifiers; predictable generation could allow session enumeration in adversarial environments
- What changed: Replaced `Math.random()` with `crypto.randomInt()` from Node.js `node:crypto` module
- What did NOT change: Slug format, word lists, collision retry logic, and fallback behavior remain identical
## Change Type
- [x] Security hardening
## Scope
- [x] Auth / tokens
## Security Impact
- New permissions/capabilities? No
- Secrets/tokens handling changed? No
- New/changed network calls? No
- Command/tool execution surface changed? No
- Data access scope changed? No
## Compatibility / Migration
- Backward compatible? Yes
- Config/env changes? No
- Migration needed? No
## Risks and Mitigations
- Risk: crypto.randomInt() has slightly different distribution characteristics
- Mitigation: For array index selection, the distribution is uniform and functionally equivalent
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Replaces `Math.random()` with `crypto.randomInt()` in session slug generation for cryptographically secure randomness. The change touches two call sites: array index selection in `randomChoice()` and the fallback suffix in `createSessionSlug()`. The fallback replacement (`randomInt(46656)` with `padStart`) is slightly more robust than the original (`Math.random().toString(36).slice(2,5)`) because it guarantees exactly 3 base-36 characters. Tests are updated to mock `node:crypto` instead of `Math.random`.
- Swapped `Math.floor(Math.random() * n)` → `randomInt(n)` for array index selection
- Replaced `Math.random().toString(36).slice(2,5)` → `randomInt(46656).toString(36).padStart(3, "0")` for fallback suffix (36³ = 46656)
- Tests now use `vi.mock("node:crypto")` with proper Vitest hoisting
- No changes to slug format, word lists, collision retry logic, or public API
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge — it's a straightforward, correct swap from Math.random() to crypto.randomInt() with no behavioral regressions.
- The change is minimal and well-scoped: two call sites replaced with cryptographically secure equivalents that produce functionally identical output. The math is correct (36³ = 46656 for 3-char base-36 strings), the fallback is actually slightly improved (padStart guarantees 3 characters), and the tests are properly updated to mock the new dependency. No API surface, slug format, or retry logic changes.
- No files require special attention.
<sub>Last reviewed commit: 1f3c0ea</sub>
<!-- greptile_other_comments_section -->
<sub>(5/5) You can turn off certain types of comments like style [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#13360: fix: widen slugifySessionKey base from 32 to 41 chars
by zerone0x · 2026-02-10
76.8%
#20653: Security: replace SHA1 with SHA256 for hash generation
by mahanandhi · 2026-02-19
74.0%
#16061: fix(sessions): tolerate invalid sessionFile metadata
by haoyifan · 2026-02-14
73.6%
#23574: security: P0 critical remediation — plugin sandbox, password hashin...
by lumeleopard001 · 2026-02-22
72.2%
#18904: fix(sandbox): restore SHA-1 in slugifySessionKey to preserve worksp...
by steflsd · 2026-02-17
72.1%
#8751: fix(security): use 0o600 permissions for session transcript files
by revenuestack · 2026-02-04
71.5%
#10745: feat: Security improvements and Windows compatibility fixes
by lluviaoscuradeldoce-design · 2026-02-06
71.3%
#22231: fix(security): redact sensitive data in session transcripts
by novalis133 · 2026-02-20
71.2%
#12296: security: persistence-only secret redaction for session transcripts
by akoscz · 2026-02-09
71.0%
#8779: fix(security): use constant-time comparison for token validation
by hleliofficiel · 2026-02-04
70.9%