Root cause: In apps/backend/src/routes/auth.ts, lines 30–31 and 158–159 call console.log('--- GITHUB OAUTH REDIRECT ---') and console.log('URL:', authUrl). The authUrl variable contains the full OAuth authorization URL including the state parameter. The state token is a 64-character hex string generated by randomBytes(32), designed specifically to be a secret CSRF protection token. Logging it to stdout in production means it ends up in any log aggregator (Datadog, CloudWatch, Loki, etc.), and anyone with log-read access can extract valid state tokens and craft CSRF attacks against the OAuth flow. The app uses app.log.error elsewhere — these are the only two places using raw console.log.
Why it matters: OAuth state tokens are security-sensitive. NIST SP 800-63B and the OAuth 2.0 Security Best Current Practice (RFC 9700) both treat unintentional disclosure of state tokens as a CSRF vulnerability. Beyond the security angle, console.log bypasses Fastify's structured logger (pino), breaking log formatting and level filtering in production. This is a quick, high-signal fix.
Affected files/functions: apps/backend/src/routes/auth.ts, /github handler lines 30–31, /google handler lines 158–159.
Current behavior: Every OAuth initiation logs the full redirect URL including the state token to raw stdout using console.log, bypassing Fastify's pino logger.
Expected behavior: Debug logging should either be removed entirely (preferred) or replaced with app.log.debug(...) which (a) uses pino structured logging, (b) is suppressed in production when log level is info or above, and (c) should never include the full URL with the state token.
Minimal fix plan:
Remove the four console.log lines (lines 30, 31, 158, 159) from auth.ts. If debug logging is truly needed during development, replace with app.log.debug({ provider: 'github' }, 'OAuth redirect initiated') — logging the provider name only, never the URL or state.
Suggested tests: Add a test that spies on console.log during a GET /auth/github request and asserts it is never called. Also assert app.log.debug is called at most once and does not contain the word state in its arguments.
Root cause: In
apps/backend/src/routes/auth.ts, lines 30–31 and 158–159 callconsole.log('--- GITHUB OAUTH REDIRECT ---')andconsole.log('URL:', authUrl). TheauthUrlvariable contains the full OAuth authorization URL including thestateparameter. The state token is a 64-character hex string generated byrandomBytes(32), designed specifically to be a secret CSRF protection token. Logging it to stdout in production means it ends up in any log aggregator (Datadog, CloudWatch, Loki, etc.), and anyone with log-read access can extract valid state tokens and craft CSRF attacks against the OAuth flow. The app usesapp.log.errorelsewhere — these are the only two places using rawconsole.log.Why it matters: OAuth
statetokens are security-sensitive. NIST SP 800-63B and the OAuth 2.0 Security Best Current Practice (RFC 9700) both treat unintentional disclosure of state tokens as a CSRF vulnerability. Beyond the security angle,console.logbypasses Fastify's structured logger (pino), breaking log formatting and level filtering in production. This is a quick, high-signal fix.Affected files/functions:
apps/backend/src/routes/auth.ts,/githubhandler lines 30–31,/googlehandler lines 158–159.Current behavior: Every OAuth initiation logs the full redirect URL including the
statetoken to raw stdout usingconsole.log, bypassing Fastify's pino logger.Expected behavior: Debug logging should either be removed entirely (preferred) or replaced with
app.log.debug(...)which (a) uses pino structured logging, (b) is suppressed in production when log level isinfoor above, and (c) should never include the full URL with the state token.Minimal fix plan:
Remove the four
console.loglines (lines 30, 31, 158, 159) fromauth.ts. If debug logging is truly needed during development, replace withapp.log.debug({ provider: 'github' }, 'OAuth redirect initiated')— logging the provider name only, never the URL or state.Suggested tests: Add a test that spies on
console.logduring aGET /auth/githubrequest and asserts it is never called. Also assertapp.log.debugis called at most once and does not contain the wordstatein its arguments.