Add file upload route with built-in security scanning (multer + pompelmi)

Author: SonoTommyCreated Apr 8, 2026Updated May 2, 2026

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 as the scan step:

javascript
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

Source: hagopj13/node-express-boilerplate