Files
picpeak/backend/src/middleware/secureStatic.js
T
paul 4e977f7624
Test Gitea Actions / test (push) Successful in 14s
continuous-integration/drone/push Build is passing
fix(security): allow serving static files from uploads directory
- Remove overly restrictive absolute path check in isPathSafe
- Strip leading slash from request path before validation
- Fixes broken favicon and watermark image previews in branding page
- Path traversal protection remains intact with ../ pattern checks

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-13 19:43:29 +02:00

46 lines
1.6 KiB
JavaScript

const path = require('path');
const express = require('express');
const { safePathJoin, isPathSafe } = require('../utils/fileSecurityUtils');
/**
* Create a secure static file serving middleware that prevents path traversal attacks
* @param {string} basePath - The base directory to serve files from
* @param {Object} options - Express static options
* @returns {Function} - Express middleware
*/
function secureStatic(basePath, options = {}) {
const normalizedBase = path.resolve(basePath);
return (req, res, next) => {
// Get the requested file path - remove leading slash for validation
const requestedPath = req.path.startsWith('/') ? req.path.substring(1) : req.path;
// Validate the path doesn't contain dangerous patterns
if (!isPathSafe(requestedPath)) {
console.warn(`Potential path traversal attempt blocked: ${requestedPath}`);
return res.status(403).json({ error: 'Access denied' });
}
try {
// Validate the full path is within the base directory
const fullPath = safePathJoin(normalizedBase, requestedPath);
// If validation passes, use express.static
const staticMiddleware = express.static(normalizedBase, {
...options,
// Disable directory listing for security
index: false,
// Don't allow dotfiles
dotfiles: 'deny'
});
return staticMiddleware(req, res, next);
} catch (error) {
// Path traversal detected
console.error(`Path traversal blocked: ${requestedPath}`, error.message);
return res.status(403).json({ error: 'Access denied' });
}
};
}
module.exports = secureStatic;