hagopj13 / hagopj13/node-express-boilerplate
Add file upload route with built-in security scanning (multer + pompelmi)
- Dominant language
- JavaScript
- Stars
- 7.7k
- Forks
- 2.3k
- PR merge metrics
- No merged PRs in 30d
Description
## Add file upload route with built-in content scanning
This picks up where issue #204 left off. That issue proposed adding file upload via multer, which makes sense. This issue proposes adding it with security scanning built in from the start, so the boilerplate ships with a safe default rather than a bare upload route that developers have to secure themselves.
### Why secure-by-default matters here
A boilerplate is copied and deployed as-is more often than it should be. If the upload route ships without content inspection, every project based on this boilerplate inherits the same gap:
- **MIME spoofing**: a file named `document.pdf` with a malicious payload passes extension and client-reported MIME checks
- **ZIP bombs**: a compressed file that expands to exhaust memory or disk during later processing
- **Office macros / active PDF content**: macro-enabled files or PDFs with embedded JavaScript actions
- **Polyglot files**: valid in multiple formats simultaneously, bypass type-based routing
These are not theoretical — they are the most common real-world upload attack vectors.
### Proposed implementation
Add a `/upload` route using `multer` (memoryStorage, not diskStorage — scan before touching disk) with [pompelmi](https://github.com/pompelmi/pompelmi) as the scan step:
```js
const multer = require('multer');
const { scanBytes, STRICT_PUBLIC_UPLOAD } = require('pompelmi');
const upload = multer({ storage: multer.memoryStorage() });
router.post('/upload', auth(), upload.single('file'), async (req, res) => {
const report = await scanBytes(req.file.buffer, {
filename: req.file.originalname,
mimeType: req.file.mimetype,
policy: STRICT_PUBLIC_UPLOAD,
failClosed: true,
});
if (report.verdict !== 'clean') {
return res.status(422).json({
code: httpStatus.UNPROCESSABLE_ENTITY,
message: `Upload blocked: ${report.reasons.join(', ')}`,
});
}
// proceed to storage (S3, disk, etc.)
res.status(200).json({ message: 'File accepted', filename: req.file.originalname });
});
```
This uses `memoryStorage` intentionally: the file is scanned in-process before any write to disk or cloud storage. pompelmi runs with zero external API calls — no cloud service, no daemon, files never leave the process.
### Scope of the PR I can submit
1. New `upload.route.js` + `upload.controller.js` following the existing project structure
2. Validation middleware for file type and size using the existing `validate` pattern
3. Tests following the existing Mocha/chai/supertest pattern
4. README section documenting the upload endpoint
Happy to submit the PR immediately — let me know if the scope looks right or if you'd prefer a narrower starting point.
---
**References**
- Picks up from: #204
- pompelmi repo: https://github.com/pompelmi/pompelmi
- License: MIT
- Coverage: Node Weekly #594, Help Net Security, Stack Overflow Blog
Contributor guide
Research direction
Start by reviewing issue #204 and the existing route, controller, and validation structure before adding the proposed upload.route.js and upload.controller.js. Follow the existing Mocha/chai/supertest pattern, then document the endpoint in the README; done means the route validates, scans, handles blocked files, and has passing tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- express, javascript, node.js
- Domain
- api, backend, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100