feat(security): sanitize SVG files on upload

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
Erik Michelson
2026-02-03 23:02:49 +01:00
parent b930fe04ce
commit f910000d2b
3 changed files with 374 additions and 49 deletions

View File

@@ -8,11 +8,22 @@ const { v4: uuidv4 } = require('uuid')
const os = require('os')
const rimraf = require('rimraf')
const isSvg = require('is-svg')
const { JSDOM } = require('jsdom')
const config = require('../../config')
const logger = require('../../logger')
const errors = require('../../errors')
let DOMPurify
try {
const window = new JSDOM('').window
global.window = window
const createDOMPurify = require('dompurify')
DOMPurify = createDOMPurify(window)
} catch (err) {
logger.error('Failed to initialize DOMPurify for SVG sanitization:', err)
}
const imageRouter = (module.exports = Router())
async function checkUploadType (filePath) {
@@ -55,6 +66,31 @@ async function checkUploadType (filePath) {
return true
}
function sanitizeSvg (filePath) {
if (!DOMPurify) {
logger.error('SVG sanitization failed: DOMPurify not initialized')
return false
}
try {
const svgContent = fs.readFileSync(filePath, 'utf8')
const cleanSvg = DOMPurify.sanitize(svgContent, {
USE_PROFILES: { svg: true, svgFilters: true }
})
if (!cleanSvg) {
logger.error('SVG sanitization resulted in empty content')
return false
}
fs.writeFileSync(filePath, cleanSvg, 'utf8')
return true
} catch (err) {
logger.error('SVG sanitization error:', err)
return false
}
}
// upload image
imageRouter.post('/uploadimage', function (req, res) {
const uploadsEnabled = config.enableUploads
@@ -97,6 +133,13 @@ imageRouter.post('/uploadimage', function (req, res) {
rimraf.sync(tmpDir)
return errors.errorBadRequest(res)
} else {
const extension = path.extname(files.image.filepath).toLowerCase()
if (extension === '.svg' && !sanitizeSvg(files.image.filepath)) {
logger.error('Image upload error: SVG sanitization failed')
rimraf.sync(tmpDir)
return errors.errorBadRequest(res)
}
logger.debug(
`SERVER received uploadimage: ${JSON.stringify(files.image)}`
)