From 10142cc15e71e23e34a4719584a7b8a80ebb07f3 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:36:30 +0100 Subject: [PATCH 1/2] fix --- Parse-Dashboard/Authentication.js | 1 + Parse-Dashboard/app.js | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Parse-Dashboard/Authentication.js b/Parse-Dashboard/Authentication.js index 00a5c3ac2..762f0234f 100644 --- a/Parse-Dashboard/Authentication.js +++ b/Parse-Dashboard/Authentication.js @@ -77,6 +77,7 @@ function initialize(app, options) { (req,res,next) => { let redirect = 'apps'; if (req.body.redirect) { + // Strip leading slash from redirect to prevent double slashes redirect = req.body.redirect.charAt(0) === '/' ? req.body.redirect.substring(1) : req.body.redirect } return passport.authenticate('local', { diff --git a/Parse-Dashboard/app.js b/Parse-Dashboard/app.js index 9908e9239..c2287aeb9 100644 --- a/Parse-Dashboard/app.js +++ b/Parse-Dashboard/app.js @@ -1062,8 +1062,12 @@ You have direct access to the Parse database through function calls, so you can } app.get('/login', csrf(), function(req, res) { - const redirectURL = req.url.includes('?redirect=') && req.url.split('?redirect=')[1].length > 1 && req.url.split('?redirect=')[1]; + let redirectURL = req.url.includes('?redirect=') && req.url.split('?redirect=')[1].length > 1 && req.url.split('?redirect=')[1]; if (!users || (req.user && req.user.isAuthenticated)) { + // Strip leading slash from redirect to prevent double slashes or malformed URLs + if (redirectURL && redirectURL.charAt(0) === '/') { + redirectURL = redirectURL.substring(1); + } return res.redirect(`${mountPath}${redirectURL || 'apps'}`); } From 1deb81f1ea2e7efb7aba163f70c6c9b6269739bd Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:57:40 +0100 Subject: [PATCH 2/2] vulnerability fixes --- Parse-Dashboard/Authentication.js | 15 ++++++++++++--- Parse-Dashboard/app.js | 22 ++++++++++++++++++---- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/Parse-Dashboard/Authentication.js b/Parse-Dashboard/Authentication.js index 762f0234f..55e274f46 100644 --- a/Parse-Dashboard/Authentication.js +++ b/Parse-Dashboard/Authentication.js @@ -76,13 +76,22 @@ function initialize(app, options) { csrf(), (req,res,next) => { let redirect = 'apps'; + let originalRedirect = null; if (req.body.redirect) { - // Strip leading slash from redirect to prevent double slashes - redirect = req.body.redirect.charAt(0) === '/' ? req.body.redirect.substring(1) : req.body.redirect + originalRedirect = req.body.redirect; + // Validate redirect to prevent open redirect vulnerability + if (originalRedirect.includes('://') || originalRedirect.startsWith('//')) { + // Reject absolute URLs and protocol-relative URLs + redirect = 'apps'; + originalRedirect = null; + } else { + // Strip leading slash from redirect to prevent double slashes + redirect = originalRedirect.charAt(0) === '/' ? originalRedirect.substring(1) : originalRedirect; + } } return passport.authenticate('local', { successRedirect: `${self.mountPath}${redirect}`, - failureRedirect: `${self.mountPath}login${req.body.redirect ? `?redirect=${req.body.redirect}` : ''}`, + failureRedirect: `${self.mountPath}login${originalRedirect ? `?redirect=${originalRedirect}` : ''}`, failureFlash : true })(req, res, next) }, diff --git a/Parse-Dashboard/app.js b/Parse-Dashboard/app.js index c2287aeb9..144851c38 100644 --- a/Parse-Dashboard/app.js +++ b/Parse-Dashboard/app.js @@ -1062,11 +1062,25 @@ You have direct access to the Parse database through function calls, so you can } app.get('/login', csrf(), function(req, res) { - let redirectURL = req.url.includes('?redirect=') && req.url.split('?redirect=')[1].length > 1 && req.url.split('?redirect=')[1]; + let redirectURL = null; + try { + const url = new URL(req.url, 'http://localhost'); + redirectURL = url.searchParams.get('redirect'); + } catch (error) { + console.warn('Invalid URL in login redirect:', error.message); + } if (!users || (req.user && req.user.isAuthenticated)) { - // Strip leading slash from redirect to prevent double slashes or malformed URLs - if (redirectURL && redirectURL.charAt(0) === '/') { - redirectURL = redirectURL.substring(1); + // Validate and sanitize redirect URL to prevent open redirect vulnerability + if (redirectURL) { + // Reject absolute URLs and protocol-relative URLs + if (redirectURL.includes('://') || redirectURL.startsWith('//')) { + redirectURL = null; + } else { + // Strip leading slash to prevent double slashes + if (redirectURL.charAt(0) === '/') { + redirectURL = redirectURL.substring(1); + } + } } return res.redirect(`${mountPath}${redirectURL || 'apps'}`); }