Open-source core · MIT · Node.js 18+
Inspect untrusted uploads before they reach storage.
Pompelmi gives Node.js teams an application-layer upload boundary. It helps routes compare claimed file metadata with real file content, apply archive controls, flag risky structures, and add optional YARA before bytes land in storage.
- Route verdict
- Return clean, suspicious, or malicious before bytes become durable state.
- Checks
- Combine type validation, archive controls, risky structure checks, and optional YARA.
- Deployment
- Run in-process, keep files local, and add adapters only where the route needs them.
Minimal route decision
Node.js 18+import { scanBytes, STRICT_PUBLIC_UPLOAD } from 'pompelmi';
const report = await scanBytes(file.buffer, {
filename: file.originalname,
mimeType: file.mimetype,
policy: STRICT_PUBLIC_UPLOAD,
failClosed: true,
});
if (report.verdict !== 'clean') return rejectUpload(report);
Install with npm install pompelmi, then wire the upload verdict into reject, quarantine, or promote logic.
Do not trust filename or client MIME
Compare claimed metadata with the bytes and structure before the route accepts the file.
Treat archives as their own risk class
ZIP traversal, expansion, entry-count, and nesting controls belong at the upload boundary.
Keep borderline files out of durable storage
Return a verdict the app can reject, quarantine, or promote with full route context intact.
Works with
Browser preview
Evaluate the verdict flow without sending a file anywhere
This preview is intentionally limited and honest. It reads selected files locally in the browser so developers can inspect the verdict UX, see a few concrete signals, and understand where the real backend integration takes over.
What it shows
- files stay in the browser and no upload request is sent
- detected type, extension, and browser-reported MIME side by side
- basic suspicious signals such as mismatches, risky PDF or SVG content, and the EICAR test string
What real backend integration adds
- route-specific policy packs and allowlists
- archive traversal, expansion, entry-count, and nesting controls
- optional YARA or other scanners plus quarantine and promotion workflows
Where to go next
Use this preview to understand the decision surface, then move to the framework guides or the Express demo when you want the server-side upload path.
Client-side preview only
This widget reads selected files locally. It never uploads them, and it does not claim to run the full backend policy path.
Files stay in your browser for this preview.
Drag files here to preview a verdict
Useful tests: a normal PDF or PNG, a renamed file, or a text file containing the EICAR test string.
What makes this preview useful
- Try a file whose extension does not match its actual bytes.
- Try a ZIP to see where the browser preview stops and the server path begins.
- Try an EICAR test file to confirm how a high-confidence verdict is presented.
Choose your path
Start from your framework or workflow
If you want the broader architecture first, start with one of the high-intent decision pages before wiring code into a specific route stack.
Express
Multer with a memory-backed upload guard.
Next.js
Node runtime route handlers for App Router.
NestJS
Module, interceptor, and service integrations.
Fastify
Early blocking in `preHandler` before storage.
Koa
Middleware-first byte inspection for routes.
Nuxt/Nitro
In-process scanning inside Nitro handlers.
CI/CD
Scan build artifacts before promotion.
S3 / object storage
Quarantine, inspect, then promote.
Who it is for
Teams that need a real upload boundary
Good fits include public or semi-trusted upload endpoints, privacy-sensitive systems, document-heavy business flows, and product teams that want the upload decision inside the application path rather than behind a generic cloud dependency.
Document uploads
PDF and Office workflows with review-friendly handling.
Image uploads
Raster routes, SVG separation, and storage decisions.
ZIP and archive uploads
Depth, expansion, entry-count, and traversal controls.
Quarantine workflows
Inspect first, store later, and promote only after review.
Three evaluation questions
Why not just extension checks?
Because filenames and client MIME claims are only the outermost layer.
Why not just ClamAV?
Signature scanning helps, but the upload gate still needs route-level and structural controls.
Why not a cloud API?
Sending files to a third party changes the privacy and latency story for every upload.
What Pompelmi is not
It is not positioned as a complete antivirus replacement. It is an application-layer control for the upload boundary.
It works well on its own, or alongside YARA, ClamAV, storage isolation, and human review flows when your environment needs deeper detection or post-upload triage.
External proof
Signals that help teams evaluate the project quickly
Pompelmi keeps the product story grounded: open source, practical docs, and public references that let teams inspect the tradeoffs for themselves.
The Overflow Issue 319: Dogfooding your SDLC
The newsletter calls out the pompelmi Q&A as a featured read.
Hottest cybersecurity open-source tools of the month: February 2026
Included in Help Net Security's monthly open-source roundup.
Defense against uploads: Q&A with OSS file scanner, pompelmi
Interview with Tommaso Bertocchi by Ryan Donovan.
Pompelmi: Open-source secure file upload scanning for Node.js
Dedicated coverage of the project and its Node.js adapters.
Translations
English is the maintained source of truth, but translated resources are available.
The public docs and root README stay focused in English. Community-maintained translations help with discovery and onboarding without duplicating the whole site.
Browse translationsKeep going
Pick the next best page for your team
The docs are the canonical integration surface. The blog and comparison pages help with architecture and rollout decisions before the first route ships.
Ship with confidence
Make the upload decision where your application still has context.
That means route-specific policy, better observability, and a cleaner line between "accepted", "blocked", and "quarantine for review".