📜 Description
The backend CORS policy is implemented as a hard-coded allowlist in backend/server.js, but it currently includes https://github-spy.etlify.app (likely meant to be netlify.app). Because credentials: true is enabled, any origin that matches the allowlist is allowed to make credentialed cross-origin requests to the auth API.
If that origin is not actually controlled by the project (typo / stale domain / later becomes attacker-controlled), this becomes a high-impact security footgun: an untrusted site could interact with /api/auth/* using the victim’s cookies and read responses.
This is also operationally risky: the real deployed frontend origin may be blocked (login/signup silently fail), pushing maintainers to “temporarily” relax CORS and accidentally introduce an actual wildcard CORS vulnerability.
Where it happens (code pointers)
backend/server.js
const allowedOrigins = ['http://localhost:5173', 'https://github-spy.etlify.app'];
credentials: true
origin: function (origin, callback) { if (!origin || allowedOrigins.indexOf(origin) !== -1) callback(null, true); ... }
Why this is critical
1) Credentialed cross-origin trust is extremely sensitive
Because sessions are cookie-based (express-session) and CORS allows credentials, any mistakenly trusted origin can:
- send authenticated requests (logout, any future authenticated endpoints),
- read the JSON responses (CORS allows the browser to expose them),
- become a stepping stone for account enumeration / session abuse.
2) “Domain drift” / typo turns into a latent security vuln
Hard-coding a production origin string means:
- renames or redeploys can break auth flows,
- “quick fixes” often lead to opening up CORS broadly,
- typos can silently create trust in the wrong origin.
Steps to reproduce (conceptual)
- Deploy backend with current CORS config.
- Host a frontend at the allowed origin (the one listed in
allowedOrigins).
- From that origin, issue
fetch(..., { credentials: "include" }) calls to:
POST /api/auth/login
GET /api/auth/logout
- Observe: browser is allowed to send cookies and read responses due to allowlisted origin +
credentials: true.
If the allowlisted domain is not actually the project’s frontend, this creates an avoidable trust boundary.
Expected behavior
- Production allowed origins are:
- correct (no typos),
- configurable per environment,
- tightly scoped (no “fail open”),
- tested.
Actual behavior
- Allowed origins are hard-coded and include a suspicious/likely incorrect domain.
- The origin callback accepts requests with missing
Origin (unnecessary for a browser-only API, and makes policy harder to reason about).
Proposed fix (non-trivial, robust)
- Move CORS config to environment:
ALLOWED_ORIGINS as a comma-separated list
- strict parsing + normalization (scheme + hostname + port)
- Remove
!origin fail-open for production (or explicitly separate “non-browser clients” behind an API token).
- Add automated tests for CORS:
- allowed origin gets
Access-Control-Allow-Origin echo + Access-Control-Allow-Credentials: true
- disallowed origin is rejected
- missing
Origin behavior matches intended policy
- Document deployment:
- specify the canonical frontend domain
- explain how to set
ALLOWED_ORIGINS safely
- (Optional) Add CSRF protection if any state-changing authenticated endpoints are added beyond login/logout.
Acceptance criteria
- Backend does not ship with a hard-coded production origin.
- Only explicitly configured origins can make credentialed cross-origin calls.
- Tests prevent regressions/typos in origin allowlisting.
📜 Description
The backend CORS policy is implemented as a hard-coded allowlist in
backend/server.js, but it currently includeshttps://github-spy.etlify.app(likely meant to benetlify.app). Becausecredentials: trueis enabled, any origin that matches the allowlist is allowed to make credentialed cross-origin requests to the auth API.If that origin is not actually controlled by the project (typo / stale domain / later becomes attacker-controlled), this becomes a high-impact security footgun: an untrusted site could interact with
/api/auth/*using the victim’s cookies and read responses.This is also operationally risky: the real deployed frontend origin may be blocked (login/signup silently fail), pushing maintainers to “temporarily” relax CORS and accidentally introduce an actual wildcard CORS vulnerability.
Where it happens (code pointers)
backend/server.jsconst allowedOrigins = ['http://localhost:5173', 'https://github-spy.etlify.app'];credentials: trueorigin: function (origin, callback) { if (!origin || allowedOrigins.indexOf(origin) !== -1) callback(null, true); ... }Why this is critical
1) Credentialed cross-origin trust is extremely sensitive
Because sessions are cookie-based (
express-session) and CORS allows credentials, any mistakenly trusted origin can:2) “Domain drift” / typo turns into a latent security vuln
Hard-coding a production origin string means:
Steps to reproduce (conceptual)
allowedOrigins).fetch(..., { credentials: "include" })calls to:POST /api/auth/loginGET /api/auth/logoutcredentials: true.If the allowlisted domain is not actually the project’s frontend, this creates an avoidable trust boundary.
Expected behavior
Actual behavior
Origin(unnecessary for a browser-only API, and makes policy harder to reason about).Proposed fix (non-trivial, robust)
ALLOWED_ORIGINSas a comma-separated list!originfail-open for production (or explicitly separate “non-browser clients” behind an API token).Access-Control-Allow-Originecho +Access-Control-Allow-Credentials: trueOriginbehavior matches intended policyALLOWED_ORIGINSsafelyAcceptance criteria