Summary
Two small OAuth hardening fixes:
generateOAuthState() (core/auth/utils.ts) throws when crypto.getRandomValues is unavailable instead of silently falling back to Math.random().
- The web OAuth callback handler (
App.tsx) parses the returned state param and rejects anything that doesn't match the expected {mode}:{authId} shape, surfacing a clear error instead of proceeding.
Why
Math.random() is not a CSRF-grade entropy source — better to fail loudly on exotic runtimes than mint guessable state. And an unparseable state on the callback is a forgery indicator; rejecting it defeats simple CSRF attempts against the callback route.
Reference implementation (PR #1510)
Re-implement informed by these changes at 33fac3f:
- core/auth/utils.ts —
generateOAuthState() throws without WebCrypto (+10/−13)
- clients/web/src/App.tsx — OAuth callback
state validation (small part of a larger diff; only the callback-handler hunks are in scope here)
Depends on
Nothing — Wave 1 foundation, parallel-safe.
Notes
- In tests that exercise the throw path, suppress expected error output from the console per AGENTS.md.
- Coverage gate ≥90 on all four dimensions for touched files.
Part of the PR #1510 decomposition (see tracking issue).
Summary
Two small OAuth hardening fixes:
generateOAuthState()(core/auth/utils.ts) throws whencrypto.getRandomValuesis unavailable instead of silently falling back toMath.random().App.tsx) parses the returnedstateparam and rejects anything that doesn't match the expected{mode}:{authId}shape, surfacing a clear error instead of proceeding.Why
Math.random()is not a CSRF-grade entropy source — better to fail loudly on exotic runtimes than mint guessable state. And an unparseablestateon the callback is a forgery indicator; rejecting it defeats simple CSRF attempts against the callback route.Reference implementation (PR #1510)
Re-implement informed by these changes at
33fac3f:generateOAuthState()throws without WebCrypto (+10/−13)statevalidation (small part of a larger diff; only the callback-handler hunks are in scope here)Depends on
Nothing — Wave 1 foundation, parallel-safe.
Notes
Part of the PR #1510 decomposition (see tracking issue).