feat(security): sanitize SVG files on upload
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
@@ -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)}`
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user