Skip to content

security: validate loginRedirect cookie to prevent open redirect#7923

Merged
NGPixel merged 1 commit intorequarks:mainfrom
kolega-ai-dev:v11-finding_10
Feb 12, 2026
Merged

security: validate loginRedirect cookie to prevent open redirect#7923
NGPixel merged 1 commit intorequarks:mainfrom
kolega-ai-dev:v11-finding_10

Conversation

@kolega-ai-dev
Copy link
Copy Markdown
Contributor

Vulnerability identified and fix provided by Kolega.dev

Open Redirect via loginRedirect Cookie

Location

server/controllers/auth.js:75-86 and client/components/login.vue:646-663

Description

The loginRedirect cookie value is read and used directly in res.redirect() (server-side) and window.location.replace() (client-side) without any validation. An attacker can set this cookie to an arbitrary external URL (e.g., https://evil.com), and when the victim authenticates, they will be redirected to the attacker-controlled site. This enables phishing attacks where the attacker's site mimics the legitimate application to steal credentials or session tokens.

While the server sets this cookie legitimately in common.js:446 using req.path (which should be a relative path), cookies can be set by JavaScript on the same domain, subdomains if cookie scope allows, or the user's browser directly.

Analysis Notes

This is a confirmed open redirect vulnerability with high practical exploitability. The loginRedirect cookie value is read at line 75 of auth.js and passed directly to res.redirect() at line 81 without validation. The same pattern exists in login.vue at line 652 with window.location.replace().

Fix Applied

Added validation to ensure the loginRedirect cookie value is a safe relative path before using it for redirection. The validation checks that the value starts with /, does not start with // (which would create a protocol-relative URL like //evil.com), and does not contain :// (which would allow absolute URLs like https://evil.com). If the cookie contains an invalid value, it is cleared and the redirect falls through to the default behavior (authResult.redirect or /). The same fix is applied to both the server-side callback handler and the client-side login response handler.

Tests/Linters Ran

  • ESLint (node_modules/.bin/eslint --format codeframe server/controllers/auth.js client/components/login.vue): Passed with no errors or warnings
  • pug-lint (node_modules/.bin/pug-lint server/views): Passed with no errors
  • Jest (node_modules/.bin/jest): server/test/helpers/page.test.js passed (3/3 tests). The Cypress integration test suite (dev/cypress/integration/setup.spec.js) has pre-existing failures unrelated to this change (Cypress globals not available in Jest runner).

Contribution Notes

  • Followed the project's existing code style (2-space indentation, single quotes, Standard JS conventions)
  • Kept the fix minimal — only the two affected redirect locations were changed
  • No new dependencies introduced
  • The existing security.securityOpenRedirect middleware in server/middlewares/security.js only strips repeating slashes from req.url and does not protect against cookie-based open redirects

The loginRedirect cookie value was used directly in res.redirect() and
window.location.replace() without validation, allowing redirection to
arbitrary external URLs. Added validation to ensure the redirect target
is a relative path before use.
@auto-assign auto-assign Bot requested a review from NGPixel February 9, 2026 20:16
@NGPixel NGPixel merged commit 7ae6635 into requarks:main Feb 12, 2026
@NGPixel
Copy link
Copy Markdown
Member

NGPixel commented Feb 12, 2026

Thanks!

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.

3 participants