Open-source upload security for Node.js. Inspect first, store later.

Pompelmi

Open-source core · MIT · Node.js upload security

Secure file uploads in Node.js before storage.

Pompelmi gives Node.js teams a route-level upload boundary. It helps the route validate claimed file types, catch archive abuse, flag risky document or binary structure, and decide between accept, quarantine, or reject before bytes become durable state.

Inspect first, store later Express / Next.js / NestJS / Fastify Archive guards + optional YARA Public examples + public references
What it is
A route-level inspection layer for untrusted uploads in Node.js.
Who it is for
Teams running public, semi-trusted, document-heavy, or object-storage-backed upload routes.
Why it matters
The first trust decision stays inside the application path instead of after storage.

Minimal route decision

npm install pompelmi
import { scanBytes, STRICT_PUBLIC_UPLOAD } from 'pompelmi';

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 rejectOrQuarantine(report);
}

Start with a clean route verdict, then wire it into reject, quarantine, or promotion logic. Framework adapters stay optional.

1

Receive into memory or quarantine

Do not trust public uploads enough to write them straight into the live bucket or a normal disk path.

2

Inspect route-specific risk

Validate claimed type, archive behavior, risky PDF or Office structure, SVG content, and optional YARA rules.

3

Return a route verdict

Let the route decide between clean, suspicious, or malicious while it still knows the workflow and user context.

4

Store, quarantine, or promote

Only accepted files reach durable state. Suspicious files can wait in a review or promotion flow instead.

Upload flow

Where Pompelmi sits in the request path

The project is not a generic after-the-fact malware queue. It belongs at the point where the application still knows the route policy, the expected file class, and whether a suspicious file should be rejected or quarantined.

1. Upload enters

Client file arrives

Browser MIME, extension, and size are useful hints, but they are not enough to trust the file yet.

2. Route gate

Fast pre-filters

Apply route limits for count, size, claimed type, and whether the route should fail closed.

3. Inspection engine

Pompelmi analyzes bytes

Detected type, archive boundaries, risky PDF or SVG structure, and optional YARA-style signals feed a route-aware verdict.

4A. Clean path

Store or promote

Only clean files reach object storage, previews, or downstream processors.

4B. Flagged path

Reject, quarantine, or review

Keep suspicious files out of the live bucket and UI path until the workflow is ready to trust them.

Request path: upload enters the route, the route applies policy-aware inspection, and only clean files move forward to storage or promotion.

Before storage, quarantine, and promotion

For simple request-response uploads, the usual sequence is receive, inspect, then store only on `clean`.

For larger or direct-to-storage flows, the safe default is quarantine first, then promote only after the scan and policy checks pass.

That keeps risky uploads out of the live bucket, preview path, OCR pipeline, or downstream parser until the application is ready to trust them.

Good fits

  • Public or semi-trusted upload endpoints that should fail closed.
  • Document-heavy business apps that need review-friendly suspicious verdicts.
  • Object-storage pipelines that should promote files only after inspection.
  • Privacy-sensitive teams that prefer local-first scanning over cloud upload APIs.

Why route-level decisions matter

Different upload controls solve different parts of the problem

Browser hints, type validation, and antivirus all help. The missing layer is usually the application decision that turns those signals into accept, reject, quarantine, or promotion.

Evaluation table

Browser MIME and extension hints

Useful for

Fast UX feedback before submit

Still missing

Attacker-controlled filenames and client MIME claims are not enough to decide trust.

Backend type validation

Useful for

Checking that bytes look like the route expects

Still missing

It still does not answer archive abuse, risky structure, or route-specific storage policy.

Antivirus or YARA only

Useful for

Known-malware matches and environment-specific signatures

Still missing

Routes still need type validation, archive controls, and before-storage handling.

Route-level upload security

Useful for

The first application decision before storage, preview, OCR, or promotion

Still missing

Nothing upstream. This is the orchestration layer that combines the other signals.

Browser preview

Evaluate the verdict flow without sending a file anywhere

The preview is intentionally honest. It is a local browser-only look at the UX and signal surface, not a claim that client-side inspection can replace the backend route.

What it shows

  • Files stay in the browser and no upload request is sent.
  • Detected type, extension, and browser-reported MIME appear side by side for quick inspection.
  • The preview surfaces obvious mismatches and suspicious signals without pretending to replace server-side checks.

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

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.

Sample scenarios

Run guided demo cases

Useful for a quick product walkthrough before choosing a real file.

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

  • Run the sample scenarios to demonstrate clean, suspicious, and malicious verdict styles instantly.
  • 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.

Use cases

Choose the deployment pattern, not a fake one-size-fits-all upload policy

Public avatar uploads, PDF intake portals, ZIP imports, and direct-to-storage promotion flows should not all share the same rules. The use-case pages map risk to route design.

See all use cases

FAQ

Questions evaluators usually ask before they wire the route

What is Pompelmi in the upload flow?

Pompelmi is the application-layer upload boundary for Node.js routes. It inspects untrusted files before disk, object storage, or downstream processors see them.

Is Pompelmi an antivirus replacement?

No. It covers route-level upload validation and structural checks. Teams can also combine it with YARA, ClamAV, quarantine, and review flows when they need deeper detection.

Can Pompelmi work with Multer, Next.js, NestJS, and Fastify?

Yes. The public docs include framework-specific integration guides for Express, Next.js, NestJS, Fastify, Koa, and Nuxt/Nitro.

Does the browser preview upload my files?

No. The preview reads selected files locally in the browser to demonstrate the verdict UX. Real upload security decisions still belong on the backend route.

Ship with context intact

Make the first upload decision while the route still knows what the file is for.

That means cleaner storage boundaries, better observability, and less guesswork when the route needs to reject, quarantine, or promote an upload.