@pompelmi/express-middleware
v0.17.0
Published
Express middleware to scan uploads with pompelmi (YARA).
Readme
@pompelmi/express-middleware
Guard your Express upload routes with pompelmi — a local-first, no-cloud file pre‑quarantine that checks uploads before they touch your app logic or storage.
Privacy-first: no outbound calls. Scans run in-process.
Install
npm i pompelmi express multer
# or: pnpm add pompelmi express multer
# or: yarn add pompelmi express multer60‑second Quickstart (TypeScript)
import express from "express";
import multer from "multer";
import { createUploadGuard } from "@pompelmi/express-middleware";
import {
CommonHeuristicsScanner,
createZipBombGuard,
composeScanners,
} from "pompelmi";
// Policy (tweak to your needs)
const policy = {
includeExtensions: ["zip", "png", "jpg", "jpeg", "pdf", "txt"],
allowedMimeTypes: [
"application/zip",
"image/png",
"image/jpeg",
"application/pdf",
"text/plain",
],
maxFileSizeBytes: 20 * 1024 * 1024, // 20MB
failClosed: true, // block on scanner/parse errors
};
// Compose scanners (stop as soon as something becomes suspicious)
const scanner = composeScanners(
[
[
"zipGuard",
createZipBombGuard({
maxEntries: 512,
maxTotalUncompressedBytes: 100 * 1024 * 1024,
maxCompressionRatio: 12,
}),
],
["heuristics", CommonHeuristicsScanner],
],
{ stopOn: "suspicious" }
);
const app = express();
const upload = multer({
storage: multer.memoryStorage(),
limits: { fileSize: policy.maxFileSizeBytes },
});
// Protect your upload route(s)
app.post(
"/upload",
upload.any(),
createUploadGuard({ ...policy, scanner }),
(req, res) => {
// The guard attaches the scan result to the request
const scan = (req as any).pompelmi ?? null;
res.json({ ok: true, scan });
}
);
app.listen(3000, () => console.log("Listening on http://localhost:3000"));Try it quickly
Run the server and in another terminal:
# Clean file
curl -F [email protected] http://localhost:3000/upload | jq
# EICAR test (if you have it) – this should be flagged as suspicious/malicious
# Replace with your own path; the repo often ships a sample under tests/samples/
# curl -F file=@tests/samples/eicar.zip http://localhost:3000/upload | jqYou’ll receive JSON containing a per‑file decision plus any notes from scanners.
API
createUploadGuard(options)
Returns an Express middleware (req, res, next) that:
- Parses the files already loaded by
multer(buffer/stream) - Runs the configured scanners
- Blocks the request on policy violations (size/type/zip bomb/etc.)
- Attaches the full scan result to
req.pompelmi
Options (forwarded to core + a few middleware specifics):
allowedMimeTypes: string[]includeExtensions: string[]maxFileSizeBytes: numberfailClosed: boolean— iftrue, unexpected errors result in a blockscanner: Scanner— fromcomposeScanners([...])mapErrorToStatus?: (reason) => number— customize HTTP codes
Core option details live in the main docs: https://pompelmi.github.io/pompelmi/#configuration
Error handling & status codes
By default the middleware maps common cases to HTTP errors:
- 413 – file too large
- 415 – unsupported/blocked MIME type or extension
- 422 – suspicious content (heuristics/YARA/zip guard)
Override via mapErrorToStatus to fit your API contract.
Accessing the scan result
app.post("/upload", upload.single("file"), createUploadGuard({ ...policy, scanner }), (req, res) => {
const scan = (req as any).pompelmi; // { files: [...], summary: {...} }
// Log, metrics, auditing, etc.
res.json({ ok: true, scan });
});Patterns
Multiple fields
app.post("/avatar", upload.single("avatar"), createUploadGuard({ ...policy, scanner }), handler)
app.post("/docs", upload.array("docs", 8), createUploadGuard({ ...policy, scanner }), handler)Deny‑list a hot type (e.g., block scripts entirely):
const policy = {
...base,
allowedMimeTypes: base.allowedMimeTypes.filter((m) => !m.startsWith("text/javascript")),
};Troubleshooting
PayloadTooLargeErrorfrom multer – increaselimits.fileSizeandmaxFileSizeBytesconsistently.- Everything gets blocked – set
failClosed: falsetemporarily and inspectreq.pompelmiin logs. - ZIPs always suspicious – relax
maxEntries/maxCompressionRatioincreateZipBombGuard.
Typings
This package ships TypeScript types. The middleware augments Request at runtime via req.pompelmi (typed as any in the example; feel free to define your own interface extension in your codebase).
See also
- Core library:
pompelmi - Koa middleware:
@pompelmi/koa-middleware - Next.js handler (App Router):
@pompelmi/next-upload
License
MIT
