Skip to content

security: add HTTP security headers to next.config.mjs#2

Open
advikdivekar wants to merge 115 commits into
mainfrom
security/http-security-headers
Open

security: add HTTP security headers to next.config.mjs#2
advikdivekar wants to merge 115 commits into
mainfrom
security/http-security-headers

Conversation

@advikdivekar

Copy link
Copy Markdown
Owner

Problem

next.config.mjs exported an empty object with no HTTP security headers configured. Every response from AlgoBuddy was sent without X-Frame-Options, X-Content-Type-Options, Content-Security-Policy, Strict-Transport-Security, Referrer-Policy, or Permissions-Policy.

This left the app exposed to four concrete attack vectors:

  • Clickjacking: the login page could be embedded in an invisible <iframe> on a malicious site and used to steal credentials.
  • MIME sniffing: browsers could interpret uploaded content with the wrong MIME type as executable JavaScript.
  • XSS amplification: no CSP meant any XSS vector could load arbitrary external scripts with no browser-level restriction.
  • Downgrade attacks: no HSTS meant users on HTTP could be SSL-stripped by a network attacker.

What changed and why

next.config.mjs — added a headers() export that attaches six security headers to every route (source: "/(.*)"):

Header Value Protects against
X-Frame-Options DENY Clickjacking
X-Content-Type-Options nosniff MIME-sniffing
Referrer-Policy strict-origin-when-cross-origin Referer leakage
Strict-Transport-Security max-age=63072000; includeSubDomains; preload SSL-stripping / downgrade
Permissions-Policy camera=(), microphone=(), geolocation=() Unwanted hardware API access
Content-Security-Policy See below XSS amplification, clickjacking

CSP sources audited from the live codebase:

  • script-src: googletagmanager.com (GA), challenges.cloudflare.com (Turnstile widget), va.vercel-scripts.com (Speed Insights), 'unsafe-inline' for the two inline scripts in layout.jsx (theme initialiser and GA config).
  • style-src: fonts.googleapis.com (Google Fonts CSS import in globals.css), 'unsafe-inline' for Tailwind.
  • font-src: fonts.gstatic.com (Google Fonts static files).
  • connect-src: *.supabase.co (auth + DB), google-analytics.com, challenges.cloudflare.com, va.vercel-scripts.com.
  • frame-src: challenges.cloudflare.com — Turnstile renders inside an iframe.
  • frame-ancestors 'none': reinforces X-Frame-Options for CSP-aware browsers.

Why this approach fixes the root cause

Using Next.js headers() in next.config.mjs is the canonical way to set headers for all routes (including static, dynamic, and API routes). It runs at the edge before any page code executes, so no response can slip through without the headers.

Steps to test

  1. Run npm run dev and execute:

    curl -sI http://localhost:3000 | grep -iE 'x-frame|x-content|strict-transport|referrer|permissions|content-security'
    

    All six headers must appear in the output.

  2. Deploy to a Vercel preview branch and run:

    curl -sI https://<preview-url>/ | grep -iE 'x-frame|x-content|strict-transport|referrer|permissions|content-security'
    
  3. Create an HTML file containing <iframe src="https://algobuddy.in/login"></iframe> and open it in a browser — the frame must be blocked with a console error referencing X-Frame-Options or frame-ancestors.

  4. Verify the app functions normally end-to-end: login (Google OAuth + email), contact form, review form, visualizer, dashboard — no CSP console errors for any legitimate resource.

Edge cases covered

  • All six headers applied to /(.*) — covers pages, API routes, and static assets.
  • frame-ancestors 'none' duplicates X-Frame-Options for modern browsers that honour CSP over the legacy header.
  • CSP allows data: for img-src to support any base64-encoded images used in visualiser pages.
  • unsafe-inline for scripts is scoped to the two identified inline scripts; no external inline attack surface is added.

No regressions

  • npm run build passes without errors or warnings.
  • Dev server confirmed to return all six headers (verified with curl -sI).
  • All existing external services (Supabase, GA, Turnstile, Speed Insights, Google Fonts) are explicitly whitelisted — nothing breaks.

Please review and merge this under GSSoC 2026.

arpitajamra-design and others added 30 commits May 21, 2026 22:26
…ear Search

Fixes PankajSingh34#43

- Added speedRef (useRef) to track latest speed value without closure issues
- Updated increaseSpeed/decreaseSpeed to keep speedRef in sync with state
- Binary Search: delay now reads from speedRef.current each recursive call
- Linear Search: delay moved inside step() so it is re-read on every iteration
…essage colors

Fixes PankajSingh34#44

- Added messageType state: 'success' | 'error' | 'warning'
- Validation errors (empty fields, invalid input, unsorted array) → yellow/warning
- Element not found (actual search result) → red/error
- Element found → green/success
- Replaced foundIndex-based color logic with messageType-driven messageClass
- Add isSortingRef to track active sort session
- Add resolveRef to immediately unblock suspended async loop on reset
- Replace raw setTimeout promises with cancellableDelay helper
- Add isSortingRef.current guard checks inside sort loops
- reset() now calls resolveRef.current() to exit pending promise instantly

Fixes: stat counters doubling, flickering bars, race conditions when
Reset is clicked mid-animation and sort is immediately restarted.
…-messages

fix: correct wrong messages in stack quiz
… boxes

Fixes PankajSingh34#86

- Added getFontSize() helper that returns text-lg, text-sm, or text-xs
  based on the string length of the displayed value
- Applied to all 7 visualizers: bubble, insertion, selection, merge,
  quicksort, binary search, linear search
- Prevents 3+ digit numbers and negative values from overflowing
  the fixed w-16 h-16 element boxes
…-reactive-animation

fix: speed slider now reactive during active animation (Binary/Linear Search)
…de-button

feat: add reusable CopyButton component for code snippets
…less-rate-limit-bypass

[Security] Replace in-memory rate limiter with global Redis sliding window
…e-algorithm-ui

Standardize algorithm visualization page layouts
…pgrst116

fix: unhandled PGRST116 error when fetching user progress
 Add robust cancellation and full reset handling to all sorting visualizers
…overflow

fix: dynamically scale font size for large and negative values in element boxes
Fixes PankajSingh34#85

- Added duplicate check using Set before starting the animation
- If duplicates detected, shows clear warning message and blocks the search
- Binary Search is only reliable on arrays with unique values
PankajSingh34 and others added 29 commits May 23, 2026 20:41
Guard Supabase initialization when env vars are missing
…-patch-12

Delete .github/workflows/IssueLabeler.yml
…-patch-14

Delete .github/workflows/labeler.yml
…-patch-15

Add labeler configuration for issue labeling
…-patch-16

Refactor labeler.yml regex patterns for labels
…-patch-20

Simplify step name in issue labeling workflow
…-patch-21

Disable versioned regex in issue labeler workflow
…-patch-22

Update issue labeler action to version 3.5
…-actions-sorting

style: Remove ArticleActions from all sorting visualizer pages to match Binary Search layout
The merge of main into security/http-security-headers left an unresolved
conflict that inserted a second `const nextConfig` block inside the first
one, making the file unparseable (SyntaxError on CI). Keeps the full
six-header version (including CSP and HSTS) and removes the duplicate.
@advikdivekar
advikdivekar force-pushed the security/http-security-headers branch from 7ac2660 to 611d425 Compare May 24, 2026 05:08
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.