diff --git a/app.js b/app.js index 768d040..c43fd65 100644 --- a/app.js +++ b/app.js @@ -59,13 +59,20 @@ const startServer = async () => { let origin; if (corsConfig.allow_origin === true) { - origin = corsConfig.whitelist; + if (corsConfig.whitelist && corsConfig.whitelist.length > 0) { + origin = corsConfig.whitelist; + } else { + origin = false; + logger.warn( + 'CORS allow_origin is true but whitelist is empty. Blocking all CORS requests for security.' + ); + } } else if (corsConfig.allow_origin === false) { origin = false; } else if (corsConfig.allow_origin === 'specific') { origin = corsConfig.whitelist; } else { - origin = corsConfig.allow_origin; // fallback for other values + origin = corsConfig.allow_origin; } const corsOptions = { diff --git a/config/paths.js b/config/paths.js index c774e22..579059c 100644 --- a/config/paths.js +++ b/config/paths.js @@ -11,3 +11,12 @@ export const getSecurePath = requestPath => { return fullPath; }; + +export const isLocalUrl = urlPath => { + try { + const url = new URL(urlPath, 'https://localhost'); + return url.origin === 'https://localhost'; + } catch { + return false; + } +}; diff --git a/routes/fileServer.js b/routes/fileServer.js index d483853..16e0bd2 100644 --- a/routes/fileServer.js +++ b/routes/fileServer.js @@ -5,7 +5,7 @@ import { join, basename, extname, resolve } from 'path'; import { Op } from 'sequelize'; import auth from 'basic-auth'; import escapeHtml from 'escape-html'; -import { SERVED_DIR, getSecurePath } from '../config/paths.js'; +import { SERVED_DIR, getSecurePath, isLocalUrl } from '../config/paths.js'; import { authenticateDownloads, authenticateUploads, @@ -228,6 +228,12 @@ router.get('*splat', authenticateDownloads, async (req, res) => { const redirectPath = req.originalUrl.endsWith('/') ? req.originalUrl : `${req.originalUrl}/`; + + if (!isLocalUrl(redirectPath)) { + logger.warn('Rejected potentially unsafe redirect', { path: redirectPath }); + return res.status(400).send('Invalid redirect path'); + } + return res.redirect(301, redirectPath); } return handleDirectoryListing(req, res, fullPath, requestPath); @@ -1085,12 +1091,22 @@ router.post('*splat', (req, res, next) => { res.status(200).send('Authenticated'); }); } else if (req.query.action === 'create-folder') { - // Redirect to new endpoint const newPath = `${req.path}/folders`; + + if (!isLocalUrl(newPath)) { + logger.warn('Rejected potentially unsafe redirect', { path: newPath }); + return res.status(400).send('Invalid redirect path'); + } + return res.redirect(307, newPath); } else if (req.query.action === 'search') { - // Redirect to new endpoint const newPath = `${req.path}/search`; + + if (!isLocalUrl(newPath)) { + logger.warn('Rejected potentially unsafe redirect', { path: newPath }); + return res.status(400).send('Invalid redirect path'); + } + return res.redirect(307, newPath); } return next();