diff --git a/Parse-Dashboard/Authentication.js b/Parse-Dashboard/Authentication.js index 00a5c3ac2..55e274f46 100644 --- a/Parse-Dashboard/Authentication.js +++ b/Parse-Dashboard/Authentication.js @@ -76,12 +76,22 @@ function initialize(app, options) { csrf(), (req,res,next) => { let redirect = 'apps'; + let originalRedirect = null; if (req.body.redirect) { - 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 9908e9239..144851c38 100644 --- a/Parse-Dashboard/app.js +++ b/Parse-Dashboard/app.js @@ -1062,8 +1062,26 @@ 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 = 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)) { + // 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'}`); }