From 76dc23c8619e7c8680107a1ba4fb30c0d65be46b Mon Sep 17 00:00:00 2001 From: dinawo Date: Thu, 12 Mar 2026 17:16:16 +0100 Subject: [PATCH] security: fix vulnerabilities and update security hardening (2026-03-12) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code security fixes: - Fixed 3 critical auth bypass bugs (user.jso, typo → user.json) in RenameFile, NewFolder, DeleteFolder API routes - Added URL validation (HTTP/HTTPS only) on ProfilPicture and BackgroundCustom endpoints to prevent stored XSS/CSS injection - Added path traversal protection in Upload.js (resolved path boundary check) - Removed unsafe-eval from CSP script-src directive - Removed information disclosure in BuildMetaData error responses - Removed unused child_process import in BuildMetaData.js Version bump: 1.2.1-beta → 1.2.2-beta --- Middlewares/securityHeadersMiddleware.js | 2 +- package.json | 2 +- routes/BuildMetaData.js | 3 +-- routes/Dpanel/API/BackgroundCustom.js | 10 ++++++++++ routes/Dpanel/API/DeleteFolfder.js | 4 ++-- routes/Dpanel/API/NewFolder.js | 2 +- routes/Dpanel/API/ProfilPicture.js | 10 ++++++++++ routes/Dpanel/API/RenameFile.js | 2 +- routes/Dpanel/API/Upload.js | 8 ++++++++ 9 files changed, 35 insertions(+), 8 deletions(-) diff --git a/Middlewares/securityHeadersMiddleware.js b/Middlewares/securityHeadersMiddleware.js index 7160f45..22517b5 100644 --- a/Middlewares/securityHeadersMiddleware.js +++ b/Middlewares/securityHeadersMiddleware.js @@ -12,7 +12,7 @@ const securityHeadersMiddleware = (req, res, next) => { 'Content-Security-Policy', [ "default-src 'self'", - "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://code.jquery.com https://cdnjs.cloudflare.com https://maxcdn.bootstrapcdn.com https://cdn.jsdelivr.net https://cdn.tailwindcss.com", + "script-src 'self' 'unsafe-inline' https://code.jquery.com https://cdnjs.cloudflare.com https://maxcdn.bootstrapcdn.com https://cdn.jsdelivr.net https://cdn.tailwindcss.com", "style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://fonts.googleapis.com", "img-src 'self' data: https: blob:", "font-src 'self' https://cdnjs.cloudflare.com https://fonts.gstatic.com", diff --git a/package.json b/package.json index 399bbd4..c1c0cfb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cdn-app/insider-myaxrin-labs-dinawo", - "version": "1.2.1-beta", + "version": "1.2.2-beta", "description": "", "main": "server.js", "scripts": { diff --git a/routes/BuildMetaData.js b/routes/BuildMetaData.js index 9d54cf5..4672c9c 100644 --- a/routes/BuildMetaData.js +++ b/routes/BuildMetaData.js @@ -1,7 +1,6 @@ const express = require('express'); const router = express.Router(); const os = require('os'); -const child_process = require('child_process'); const packageJson = require('../package.json'); const fs = require('fs'); const path = require('path'); @@ -64,7 +63,7 @@ router.get('/', async (req, res) => { res.json(buildMetadata); } catch (error) { console.error('Error in /build-metadata: ', error); - res.status(500).send('Error in /build-metadata: ' + error.toString()); + res.status(500).send('Internal server error'); } }); diff --git a/routes/Dpanel/API/BackgroundCustom.js b/routes/Dpanel/API/BackgroundCustom.js index 36c116d..395659f 100644 --- a/routes/Dpanel/API/BackgroundCustom.js +++ b/routes/Dpanel/API/BackgroundCustom.js @@ -13,6 +13,16 @@ router.post('/wallpaper', (req, res) => { return res.status(400).send('No wallpaper URL provided.'); } + // Validate URL to prevent XSS/CSS injection via malicious URLs + try { + const parsed = new URL(wallpaperUrl); + if (!['http:', 'https:'].includes(parsed.protocol)) { + return res.status(400).send('Invalid URL protocol. Only HTTP/HTTPS allowed.'); + } + } catch { + return res.status(400).send('Invalid URL format.'); + } + updateUserWallpaper(userId, wallpaperUrl, res); }); diff --git a/routes/Dpanel/API/DeleteFolfder.js b/routes/Dpanel/API/DeleteFolfder.js index 0e0b073..0a716e1 100644 --- a/routes/Dpanel/API/DeleteFolfder.js +++ b/routes/Dpanel/API/DeleteFolfder.js @@ -129,9 +129,9 @@ function authenticateToken(req, res, next) { return res.status(401).json({ message: 'Unauthorized' }); } - fs.readFile(path.join(__dirname, '../../../data', 'user.jso,'), 'utf8', (err, data) => { + fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => { if (err) { - console.error('Error reading user.jso,:', err); + console.error('Error reading user.json:', err); return res.status(401).json({ message: 'Unauthorized' }); } diff --git a/routes/Dpanel/API/NewFolder.js b/routes/Dpanel/API/NewFolder.js index 341fa14..a823cca 100644 --- a/routes/Dpanel/API/NewFolder.js +++ b/routes/Dpanel/API/NewFolder.js @@ -105,7 +105,7 @@ function authenticateToken(req, res, next) { return res.status(401).json({ message: 'Unauthorized' }); } - fs.readFile(path.join(__dirname, '../../../data', 'user.jso,'), 'utf8', (err, data) => { + fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => { if (err) { console.error('Error reading user.json:', err); return res.status(401).json({ message: 'Unauthorized' }); diff --git a/routes/Dpanel/API/ProfilPicture.js b/routes/Dpanel/API/ProfilPicture.js index 75b152c..c79bee1 100644 --- a/routes/Dpanel/API/ProfilPicture.js +++ b/routes/Dpanel/API/ProfilPicture.js @@ -13,6 +13,16 @@ router.post('/', (req, res) => { return res.status(400).send('No profile picture URL provided.'); } + // Validate URL to prevent XSS/injection via malicious URLs + try { + const parsed = new URL(profilePictureUrl); + if (!['http:', 'https:'].includes(parsed.protocol)) { + return res.status(400).send('Invalid URL protocol. Only HTTP/HTTPS allowed.'); + } + } catch { + return res.status(400).send('Invalid URL format.'); + } + updateUserProfilePicture(userId, profilePictureUrl, res); }); diff --git a/routes/Dpanel/API/RenameFile.js b/routes/Dpanel/API/RenameFile.js index 30c68b7..67df6c5 100644 --- a/routes/Dpanel/API/RenameFile.js +++ b/routes/Dpanel/API/RenameFile.js @@ -107,7 +107,7 @@ function authenticateToken(req, res, next) { } } - fs.readFile(path.join(__dirname, '../../../data', 'user.jso,'), 'utf8', (err, data) => { + fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => { if (err) { console.error('Error reading user.json:', err); return res.status(401).json({ message: 'Unauthorized' }); diff --git a/routes/Dpanel/API/Upload.js b/routes/Dpanel/API/Upload.js index 795e6aa..c8d097c 100644 --- a/routes/Dpanel/API/Upload.js +++ b/routes/Dpanel/API/Upload.js @@ -68,6 +68,14 @@ router.post('/', (req, res) => { const filename = fields.filename ? fields.filename[0] : file.originalFilename; const filePath = path.join(userDir, filename); + // Path traversal protection: ensure resolved path stays within user directory + const resolvedUserDir = path.resolve(process.cwd(), 'cdn-files', userName); + const resolvedFilePath = path.resolve(filePath); + if (!resolvedFilePath.startsWith(resolvedUserDir + path.sep) && resolvedFilePath !== resolvedUserDir) { + if (fs.existsSync(file.path)) fs.unlinkSync(file.path); + return res.status(403).send('Path traversal detected'); + } + // Récupérer les champs supplémentaires const expiryDate = fields.expiryDate ? fields.expiryDate[0] : ''; const password = fields.password ? fields.password[0] : ''; -- 2.49.1