Skip to content

security: remove INSECURE_DEFAULT JWT_SECRET fallback - #1

Open
isaJrKai wants to merge 1 commit into
mainfrom
fix/jwt-secret-fallback
Open

security: remove INSECURE_DEFAULT JWT_SECRET fallback#1
isaJrKai wants to merge 1 commit into
mainfrom
fix/jwt-secret-fallback

Conversation

@isaJrKai

@isaJrKai isaJrKai commented Jun 25, 2026

Copy link
Copy Markdown
Owner

What this fixes

Removes the INSECURE_DEFAULT hardcoded JWT secret fallback from both src/lib/auth.ts and src/lib/auth-edge.ts.

The vulnerability

Previously, both files contained:

const INSECURE_DEFAULT = "DEV-ONLY-INSECURE-SECRET-DO-NOT-USE-IN-PRODUCTION-change-me-please";
const JWT_SECRET_STRING = process.env.JWT_SECRET ?? INSECURE_DEFAULT;
  • auth.ts had a production-only check that threw if JWT_SECRET was missing — so the fallback only fired in dev.
  • auth-edge.ts (used by middleware, runs in Edge runtime) had no such check — if JWT_SECRET was accidentally unset on Vercel, middleware would silently use the hardcoded string for JWT verification.

Since this repo is public, anyone could read the source, see the INSECURE_DEFAULT constant, and forge valid JWTs against any deployment where JWT_SECRET was misconfigured.

The fix

  • Removed the INSECURE_DEFAULT constant entirely from both files.
  • Both files now throw at module load if JWT_SECRET is missing or shorter than 32 characters.
  • Behavior is identical in dev and prod — fail fast, never silently use a known string.
  • Vercel will mark the deployment as failed if JWT_SECRET is unset, which is the correct behavior (better a failed deploy than a silently-insecure one).

Files changed

  • src/lib/auth.ts — removed fallback + production-only check, replaced with unconditional throw
  • src/lib/auth-edge.ts — same treatment, plus explanatory comment about Edge runtime behavior

+21 / -11 lines across 2 files.

Verification

  • npx tsc --noEmit — clean
  • npx eslint src/lib/auth.ts src/lib/auth-edge.ts — clean
  • ✅ Behavior verified locally: app throws on startup if JWT_SECRET is unset

Pre-deploy checklist

Before merging, verify on Vercel:

  1. Go to Project Settings → Environment Variables
  2. Confirm JWT_SECRET is set for Production (should be a 64+ char random string)
  3. If unsure, regenerate: node -e "console.log(require('crypto').randomBytes(48).toString('base64url'))"
  4. Update the env var, then merge this PR

If JWT_SECRET is already set correctly on Vercel (which it should be — the app is currently working), this PR is safe to merge with zero downtime.

Summary by CodeRabbit

  • Bug Fixes
    • Added stricter startup checks for JWT secret configuration.
    • The app now stops immediately if the JWT secret is missing or too short, instead of using a weak fallback value.
    • Improved error messaging to make configuration issues easier to spot during deployment.

Both auth.ts and auth-edge.ts previously fell back to a hardcoded constant
string when JWT_SECRET env var was missing. auth.ts had a production-only
check that threw, but auth-edge.ts (used by middleware, runs in Edge runtime)
had NO check — meaning if JWT_SECRET was accidentally unset on Vercel,
middleware would silently use a publicly-known string for JWT verification.

Anyone reading the public repo could forge valid JWTs in that scenario.

Fix: remove INSECURE_DEFAULT entirely. Both files now throw at module load
if JWT_SECRET is missing or shorter than 32 chars. This applies in dev and
prod — fail fast, never silently use a known string.

Vercel will mark the deployment as failed if JWT_SECRET is unset, which is
the correct behavior (better a failed deploy than a silently-insecure one).
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Both auth modules now validate process.env.JWT_SECRET during module initialization and throw if it is missing or shorter than 32 characters. The insecure default JWT secret fallback was removed.

Changes

JWT secret validation

Layer / File(s) Summary
Module-load validation
src/lib/auth.ts, src/lib/auth-edge.ts
Both auth modules now reject missing or short JWT secrets at load time and no longer use the insecure fallback secret.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 I hop through code, oh what a sight,
No secret sneaks in from the night.
JWT now starts with guardrails new,
Safe little burrows, steady and true.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main security change: removing the insecure JWT secret fallback.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/jwt-secret-fallback

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed: one or more packages not found in the registry.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/auth-edge.ts`:
- Around line 4-6: The security check in auth-edge is only triggered at runtime,
so the build can still pass when JWT_SECRET is missing. Update the build/deploy
flow by wiring the existing security:check script into the main build path (for
example in the package.json build script used by next build/vercel build) so the
required env var is validated before deployment; keep the check associated with
the auth-edge middleware startup path so the failure happens during build, not
first request.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5dfaabec-4af0-4bf3-8797-1fa1d21a4ec2

📥 Commits

Reviewing files that changed from the base of the PR and between 7053878 and ca6fbcd.

📒 Files selected for processing (2)
  • src/lib/auth-edge.ts
  • src/lib/auth.ts

Comment thread src/lib/auth-edge.ts
Comment on lines +4 to +6
// Edge runtime (middleware) imports this module, so the throw happens at
// middleware load time — Vercel will mark the deployment as failed if
// JWT_SECRET is unset, rather than silently using a known string.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Description: Check whether JWT_SECRET validation is wired into build/deploy scripts.
# Expectation: package/vercel config should run scripts/security-check.js or an equivalent JWT_SECRET check before deployment succeeds.

fd -t f '^(package\.json|vercel\.json)$' . -x sh -c '
  echo "== $1 ==";
  if [ "$(basename "$1")" = "package.json" ]; then
    jq ".scripts // {}" "$1"
  else
    cat "$1"
  fi
' sh {}

rg -n -C2 'security-check|JWT_SECRET|next build|vercel' package.json vercel.json scripts/security-check.js 2>/dev/null || true

Repository: isaJrKai/planned

Length of output: 296


🏁 Script executed:

cd isaJrKai/planned
# Check package.json scripts directly
cat package.json | grep -A 20 '"scripts"'
# Check vercel.json content
cat vercel.json 2>/dev/null || echo "vercel.json not found"
# Check if security-check.js exists and what it does
cat scripts/security-check.js 2>/dev/null | head -30 || echo "security-check.js not found"
# Check Next.js middleware config or vercel build config for pre-deploy hooks
if [ -f vercel.json ]; then
  cat vercel.json
fi

# Look for build hooks in next.config.js
grep -n 'vercel\|build\|env' next.config.js 2>/dev/null || echo "next.config.js not found or no relevant lines"

Repository: isaJrKai/planned

Length of output: 2602


🏁 Script executed:

grep -r "security:check" . --include="*.json" --include="*.yml" --include="*.yaml" --include="*.js" --include="*.ts" 2>/dev/null | head -20

Repository: isaJrKai/planned

Length of output: 225


🏁 Script executed:

grep -A5 -B5 "security" package.json vercel.json 2>/dev/null || grep -n "security" package.json
grep -n "postbuild\|prebuild" package.json 2>/dev/null || echo "No prebuild/postbuild hooks"
ls -la scripts/ 2>/dev/null || echo "No scripts directory"

Repository: isaJrKai/planned

Length of output: 1091


Verify build/deploy pipeline invokes the security check

The security:check script exists but is not wired into next build, vercel build, or any postinstall hook. Consequently, if JWT_SECRET is missing on Vercel, the build will not fail immediately; the error will occur only at runtime (when the middleware first executes).

Please explicitly fail the build if a required environment variable is missing by running the check as part of the build script.

{
  "package.json": {
    "scripts": {
      "build": "security:check && prisma generate && next build"
    }
  }
}

Alternatively, enforce the check in vercel.json using a build hook if available, though modifying package.json scripts is the standard approach for Next.js projects.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/auth-edge.ts` around lines 4 - 6, The security check in auth-edge is
only triggered at runtime, so the build can still pass when JWT_SECRET is
missing. Update the build/deploy flow by wiring the existing security:check
script into the main build path (for example in the package.json build script
used by next build/vercel build) so the required env var is validated before
deployment; keep the check associated with the auth-edge middleware startup path
so the failure happens during build, not first request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant