Skip to content

Replace wildcard CORS with explicit ALLOWED_ORIGINS allowlist#379

Closed
advikdivekar wants to merge 1 commit into
GitMetricsLab:mainfrom
advikdivekar:security/cors-origin-allowlist
Closed

Replace wildcard CORS with explicit ALLOWED_ORIGINS allowlist#379
advikdivekar wants to merge 1 commit into
GitMetricsLab:mainfrom
advikdivekar:security/cors-origin-allowlist

Conversation

@advikdivekar
Copy link
Copy Markdown
Contributor

What is the problem

backend/server.js line 15 configures app.use(cors('*')). This tells every browser that any origin on the internet is permitted to read API responses, completely removing the Same-Origin Policy as a defence layer.

The impact is twofold. First, every unauthenticated endpoint is freely readable from any origin with no review — a page on evil.com can fetch() the API and read the full JSON response. Second, every future endpoint added by any contributor is silently exposed by the same wildcard with no per-origin review step, creating a permanently expanding attack surface.

What was changed

backend/server.js

  • Removed cors('*').
  • Reads process.env.ALLOWED_ORIGINS (comma-separated string) and splits it into an array of permitted origins, defaulting to http://localhost:5173 so local development requires no config change.
  • Passes an origin callback to the cors() call that allows requests with no Origin header (server-to-server / health-check calls) and rejects all other origins not on the list with an error.
  • Adds credentials: true so session cookies are accepted on cross-origin requests from listed origins.
  • Restricts allowed methods to GET and POST and allowed headers to Content-Type.

backend/.env.sample

  • Documents ALLOWED_ORIGINS so developers know to set the correct production domain when deploying.

Why this approach

An allowlist driven by an environment variable means dev, staging, and production each declare only their own frontend origin with no code changes between environments. The !origin guard in the callback is necessary to allow server-to-server calls (monitoring, Docker health checks) which browsers never make and therefore carry no Origin header. Without this guard those calls would be rejected by the CORS middleware even though they pose no cross-origin risk.

credentials: true is required alongside the explicit allowlist — CORS wildcard and credentials cannot coexist in browsers, so enabling credentials is only safe once the wildcard is gone.

How to test

  1. From a browser tab at any unlisted origin (e.g., open DevTools on any other website), run:
    fetch('http://localhost:5000/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' })
    The browser must throw a CORS policy error and block the response.
  2. From http://localhost:5173, the same request must succeed and return a JSON response.
  3. Confirm the Access-Control-Allow-Origin response header shows the exact requesting origin (e.g., http://localhost:5173), not *.
  4. Set ALLOWED_ORIGINS=http://localhost:5173,https://myapp.com in the backend .env and confirm both origins are permitted while a third is rejected.

Edge cases covered

  • Requests with no Origin header (server-to-server, curl without -H) are allowed through without being on the list.
  • The ALLOWED_ORIGINS value is trimmed after splitting so accidental whitespace around the comma does not silently reject a valid origin.
  • The fallback default http://localhost:5173 means existing local development setups work without any .env changes.

Verification

  • Root cause fully resolved
  • All edge cases handled
  • No regressions — existing routes continue to function from the permitted origin
  • No other files touched; isolated to the CORS configuration block only
  • Code matches project style and conventions

Labels: type:security level:intermediate gssoc:approved

Closes #374

Please assign this PR to me under GSSoC 2026.

cors('*') permitted any origin to read API responses, removing the
Same-Origin Policy as a defence layer for all current and future
endpoints with no per-origin review.

Replace with an origin callback that checks against an ALLOWED_ORIGINS
environment variable (comma-separated, defaults to localhost:5173 for
local development). Enable credentials:true so session cookies work
on cross-origin requests from the listed frontend.

Document ALLOWED_ORIGINS in .env.sample so developers set the correct
production domain when deploying.

Closes GitMetricsLab#374
@netlify
Copy link
Copy Markdown

netlify Bot commented May 21, 2026

Deploy Preview for github-spy ready!

Name Link
🔨 Latest commit af3bac1
🔍 Latest deploy log https://app.netlify.com/projects/github-spy/deploys/6a0f5f0e41478e0008bdd0ec
😎 Deploy Preview https://deploy-preview-379--github-spy.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

Warning

Rate limit exceeded

@advikdivekar has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 51 minutes and 23 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1aed0d43-7b18-47bd-a635-3cc06005897c

📥 Commits

Reviewing files that changed from the base of the PR and between 9d34c19 and af3bac1.

📒 Files selected for processing (2)
  • backend/.env.sample
  • backend/server.js
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Security] Wildcard CORS (cors('*')) Configured on Authenticated Backend API

2 participants