feat(csrf): add Origin/Referer CSRF protection (#1878)#1983
Conversation
|
@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. |
GSSoC Label Checklist 🏷️@Priyanshu-byte-coder — please apply the appropriate labels before merging: Difficulty (pick one):
Quality (optional):
Validation (required to score):
|
|
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. |
|
This PR has merge conflicts with 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 |
f4eef48 to
393057c
Compare
|
Confirmed the 2 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 ( |
b469777
into
Priyanshu-byte-coder:main
|
🎉 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! |
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.tswithvalidateCsrf(),isStateChangingMethod(), andisCsrfExempt(). The utility readsALLOWED_ORIGINSfrom env (auto-includingNEXTAUTH_URL,NEXT_PUBLIC_APP_URL, andhttp://localhost:3000in 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.tswith a CSRF check block before the rate-limit section, and expandedconfig.matcherfrom 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 theALLOWED_ORIGINSenv var to.env.example.Local Testing Execution
npm run type-check- zero errorsnpm run lint- zero new warningsnpx playwright test e2e/csrf.spec.js --workers=1- 5/5 passednpx playwright test --workers=1- 23 total, 19 pass + 4 pre-existing failures onupstream/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 changeDesired Review Feedback Type
Edge-case review of the origin-matching logic in
validateCsrf()- specifically thestartsWithsuffix 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.