Bug Description
The logout endpoint in backend/routes/auth.js is registered as a GET request. HTTP GET is defined as a safe, idempotent method that must not trigger state changes. Using GET for logout violates this contract and makes the endpoint exploitable via Cross-Site Request Forgery (CSRF): any page on the web can silently log out an authenticated user without any user interaction.
Affected File
backend/routes/auth.js line 43
router.get("/logout", (req, res) => {
req.logout((err) => {
if (err) return res.status(500).json({ message: 'Logout failed', error: err.message });
res.status(200).json({ message: 'Logged out successfully' });
});
});
How the Attack Works
Because GET requests are triggered automatically by the browser in many contexts, an attacker can force a logout with zero user interaction using any of the following:
<!-- Embedded in any page the victim visits -->
<img src="https://github-spy.etlify.app/api/auth/logout" width="0" height="0">
Or via a <link rel="prefetch">, a CSS background URL, or a JavaScript fetch. The browser sends the request including the session cookie, the session is destroyed, and the user finds themselves unexpectedly signed out. The attacker gains no data, but for a service where authentication is required for all useful functionality this constitutes a targeted denial-of-service against specific users.
Additionally, since the session cookie currently lacks a SameSite attribute (tracked separately in issue #554), cross-site requests automatically carry the cookie, making this attack immediately practical without any additional bypass.
Steps to Reproduce
- Log in via
POST /api/auth/login.
- From any origin (or a new tab via the browser address bar), visit:
GET /api/auth/logout.
- Navigate back to the app and observe the session has been destroyed.
The address bar access demonstrates the attack vector directly, since a <img> or <link> tag would behave identically from the browser's perspective.
Expected Behavior
Logout must be a POST endpoint protected against CSRF. Because the existing session-based auth does not use a CSRF token, the minimum safe change is:
- Change the route to
router.post("/logout", ...).
- Update the frontend to send
POST /api/auth/logout (with credentials: 'include' so the session cookie is included).
With the SameSite: strict cookie fix also applied, POST-based logout with credentials provides adequate CSRF protection for a same-origin-only application.
Suggested Fix
// backend/routes/auth.js
router.post("/logout", (req, res) => {
req.logout((err) => {
if (err) return res.status(500).json({ message: 'Logout failed', error: err.message });
req.session.destroy(() => {
res.clearCookie('connect.sid');
res.status(200).json({ message: 'Logged out successfully' });
});
});
});
Note: req.session.destroy() and res.clearCookie() are added here because req.logout() alone does not invalidate the server-side session data or remove the cookie from the browser. Without them, the old session ID remains valid on the server until it naturally expires.
Severity
High / Security - Any authenticated user can be logged out without consent by a third-party page. Combined with the missing SameSite cookie attribute, this is trivially exploitable today.
This issue is raised under GSSoC 2026 for open-source contribution.
Bug Description
The logout endpoint in
backend/routes/auth.jsis registered as aGETrequest. HTTP GET is defined as a safe, idempotent method that must not trigger state changes. Using GET for logout violates this contract and makes the endpoint exploitable via Cross-Site Request Forgery (CSRF): any page on the web can silently log out an authenticated user without any user interaction.Affected File
backend/routes/auth.jsline 43How the Attack Works
Because GET requests are triggered automatically by the browser in many contexts, an attacker can force a logout with zero user interaction using any of the following:
Or via a
<link rel="prefetch">, a CSS background URL, or a JavaScriptfetch. The browser sends the request including the session cookie, the session is destroyed, and the user finds themselves unexpectedly signed out. The attacker gains no data, but for a service where authentication is required for all useful functionality this constitutes a targeted denial-of-service against specific users.Additionally, since the session cookie currently lacks a
SameSiteattribute (tracked separately in issue #554), cross-site requests automatically carry the cookie, making this attack immediately practical without any additional bypass.Steps to Reproduce
POST /api/auth/login.GET /api/auth/logout.The address bar access demonstrates the attack vector directly, since a
<img>or<link>tag would behave identically from the browser's perspective.Expected Behavior
Logout must be a
POSTendpoint protected against CSRF. Because the existing session-based auth does not use a CSRF token, the minimum safe change is:router.post("/logout", ...).POST /api/auth/logout(withcredentials: 'include'so the session cookie is included).With the
SameSite: strictcookie fix also applied, POST-based logout with credentials provides adequate CSRF protection for a same-origin-only application.Suggested Fix
Note:
req.session.destroy()andres.clearCookie()are added here becausereq.logout()alone does not invalidate the server-side session data or remove the cookie from the browser. Without them, the old session ID remains valid on the server until it naturally expires.Severity
High / Security - Any authenticated user can be logged out without consent by a third-party page. Combined with the missing
SameSitecookie attribute, this is trivially exploitable today.This issue is raised under GSSoC 2026 for open-source contribution.