fix(security): re-apply SVG CSP on the direct favicon route (PR #603 blocker)
The /favicon.ico + /apple-touch-icon routes stream the file directly, bypassing the secureStatic middleware that locks down served SVGs. An admin-uploaded SVG favicon with <script> would then run at the top-level origin (stored XSS). Re-apply the same CSP (default-src 'none') + nosniff for .svg here, mirroring secureStatic.js. Reported in the #603 review.
This commit is contained in:
@@ -585,6 +585,15 @@ app.get(
|
||||
const resolved = path.resolve(path.join(uploadsRoot, rel));
|
||||
// Path containment — never serve outside the uploads dir.
|
||||
if (resolved.startsWith(uploadsRoot + path.sep) && fs.existsSync(resolved)) {
|
||||
// This route streams the file directly, bypassing the secureStatic
|
||||
// middleware — so re-apply its SVG hardening here. An admin-uploaded
|
||||
// SVG favicon could contain <script>; served at the top-level
|
||||
// /favicon.ico origin without CSP that would be stored XSS. Keep in
|
||||
// sync with secureStatic.js.
|
||||
if (/\.svg$/i.test(resolved)) {
|
||||
res.setHeader('Content-Security-Policy', "default-src 'none'; style-src 'unsafe-inline'; img-src 'self' data:");
|
||||
res.setHeader('X-Content-Type-Options', 'nosniff');
|
||||
}
|
||||
res.setHeader('Cache-Control', 'public, max-age=86400');
|
||||
return res.sendFile(resolved);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user