Skip to content

feat(csrf): add Origin/Referer CSRF protection (#1878)#1983

Merged
Priyanshu-byte-coder merged 1 commit into
Priyanshu-byte-coder:mainfrom
ask-z4ch:feat/csrf-protection
Jun 4, 2026
Merged

feat(csrf): add Origin/Referer CSRF protection (#1878)#1983
Priyanshu-byte-coder merged 1 commit into
Priyanshu-byte-coder:mainfrom
ask-z4ch:feat/csrf-protection

Conversation

@ask-z4ch
Copy link
Copy Markdown
Contributor

@ask-z4ch ask-z4ch commented Jun 3, 2026

Closes #1878

Changes made: added Origin/Referer CSRF validation in src/lib/csrf.ts + middleware integration in src/middleware.ts

Testing done: npm run type-check (zero errors), npm run lint (zero new warnings), npx playwright test e2e/csrf.spec.js (5/5 passed), npx playwright test --workers=1 (19 pass, 4 pre-existing failures - zero regressions)

════════════════════════════════════════

Purpose & Rationale

The app had no CSRF protection on API state-changing methods. A compromised site could forge POST/PUT/PATCH/DELETE requests from a logged-in user's browser, enabling unauthorized goal creation, settings changes, or data mutation. This adds Origin/Referer header validation at the middleware layer to block cross-origin forgeries while exempting webhook endpoints that receive requests from external services.

Technical Resolution Details

Added src/lib/csrf.ts with validateCsrf(), isStateChangingMethod(), and isCsrfExempt(). The utility reads ALLOWED_ORIGINS from env (auto-including NEXTAUTH_URL, NEXT_PUBLIC_APP_URL, and http://localhost:3000 in dev), then validates incoming Origin or Referer headers against the allowed set. Exempted routes are webhook prefixes (/api/webhooks/*) and rate-limited auth/metrics paths.

Updated src/middleware.ts with a CSRF check block before the rate-limit section, and expanded config.matcher from three specific prefix patterns to a single catch-all /api/:path*, ensuring CSRF coverage across all API routes.

Added 5 E2E tests in e2e/csrf.spec.js, plus the ALLOWED_ORIGINS env var to .env.example.

Local Testing Execution

  1. npm run type-check - zero errors
  2. npm run lint - zero new warnings
  3. npx playwright test e2e/csrf.spec.js --workers=1 - 5/5 passed
  4. npx playwright test --workers=1 - 23 total, 19 pass + 4 pre-existing failures on upstream/main (auth pattern from unmerged [BUG] fix: E2E dashboard-widgets smoke tests consistently fail in CI due to missing auth session #1972), zero regressions from this change

Desired Review Feedback Type

Edge-case review of the origin-matching logic in validateCsrf() - specifically the startsWith suffix handling and whether the webhook exemption list covers all external-receiver endpoints.

Integrity & AI Usage Disclosure

In compliance with the GSSoC 2026 AI Conduct rules, I disclose that AI tools were used solely as learning and boilerplate aids. The final logic was fully reviewed, tested, and manually adapted to match human styling and clean-code design.

@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 3, 2026

@ask-z4ch is attempting to deploy a commit to the PRIYANSHU DOSHI's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added gssoc26 GSSoC 2026 contribution type:feature GSSoC type bonus: new feature type:security GSSoC type bonus: security (+20 pts) type:testing GSSoC type bonus: tests (+10 pts) labels Jun 3, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

GSSoC Label Checklist 🏷️

@Priyanshu-byte-coder — please apply the appropriate labels before merging:

Difficulty (pick one):

  • level:beginner — 20 pts
  • level:intermediate — 35 pts
  • level:advanced — 55 pts
  • level:critical — 80 pts

Quality (optional):

  • quality:clean — ×1.2 multiplier
  • quality:exceptional — ×1.5 multiplier

Validation (required to score):

  • gssoc:approved — counts for points
  • gssoc:invalid / gssoc:spam / gssoc:ai-slop — does not score

Type labels (type:*) are auto-detected from files and title. Review and adjust if needed.
Points formula: (difficulty × quality_multiplier) + type_bonus

@ask-z4ch
Copy link
Copy Markdown
Contributor Author

ask-z4ch commented Jun 3, 2026

@Priyanshu-byte-coder

The 4 dashboard-widgets.spec.js and notifications.spec.js failures visible in the full suite run are pre-existing on upstream/main.

They require the auth token encoding fixes from #1976 (fixes #1972 ). This PR contains zero changes to those spec files; the 5 CSRF-specific E2E tests all pass cleanly. Once #1976 is merged, the full suite will be green.

@Priyanshu-byte-coder
Copy link
Copy Markdown
Owner

This PR has merge conflicts with main — the src/middleware.ts was recently refactored in #1940 (auth rate limiting). Please rebase:

git fetch origin
git rebase origin/main
# Resolve conflicts in src/middleware.ts carefully — integrate the CSRF checks alongside the new auth rate limiting logic
git push --force-with-lease

@ask-z4ch ask-z4ch force-pushed the feat/csrf-protection branch from f4eef48 to 393057c Compare June 4, 2026 06:47
@ask-z4ch
Copy link
Copy Markdown
Contributor Author

ask-z4ch commented Jun 4, 2026

@Priyanshu-byte-coder

Confirmed the 2 theme.spec.js failures are pre-existing on upstream/main - tracked in #2001.

They're caused by a UI refactor that replaced the theme toggle button with a combobox, unrelated to this PR.

All 5 CSRF-specific tests (e2e/csrf.spec.js) pass cleanly, and no other tests regressed.

@Priyanshu-byte-coder Priyanshu-byte-coder added gssoc:approved GSSoC: PR approved for scoring quality:clean GSSoC: Clean quality multiplier (×1.2) level:advanced GSSoC: Advanced difficulty (55 pts) labels Jun 4, 2026
@Priyanshu-byte-coder Priyanshu-byte-coder merged commit b469777 into Priyanshu-byte-coder:main Jun 4, 2026
9 of 10 checks passed
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 4, 2026

🎉 Merged! Thanks for contributing to DevTrack.

If the project has been useful to you, a ⭐ star on the repo is the easiest way to support it — it helps DevTrack get discovered by more developers.

Keep an eye on open issues for your next contribution!

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

Labels

gssoc:approved GSSoC: PR approved for scoring gssoc26 GSSoC 2026 contribution level:advanced GSSoC: Advanced difficulty (55 pts) quality:clean GSSoC: Clean quality multiplier (×1.2) type:feature GSSoC type bonus: new feature type:security GSSoC type bonus: security (+20 pts) type:testing GSSoC type bonus: tests (+10 pts)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Missing CSRF protection on state-changing API routes — cross-site requests can modify user data

2 participants