pompelmi 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +158 -12
- package/dist/pompelmi.cjs +10 -8
- package/dist/pompelmi.cjs.map +1 -1
- package/dist/pompelmi.esm.js +10 -8
- package/dist/pompelmi.esm.js.map +1 -1
- package/package.json +36 -20
package/README.md
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<!-- Language Selector -->
|
|
4
|
+
<p>
|
|
5
|
+
<strong>Read this in other languages:</strong><br/>
|
|
6
|
+
<a href="docs/i18n/README.it.md">🇮🇹 Italiano</a> •
|
|
7
|
+
<a href="docs/i18n/README.fr.md">🇫🇷 Français</a> •
|
|
8
|
+
<a href="docs/i18n/README.es.md">🇪🇸 Español</a> •
|
|
9
|
+
<a href="docs/i18n/README.de.md">🇩🇪 Deutsch</a> •
|
|
10
|
+
<a href="docs/i18n/README.ja.md">🇯🇵 日本語</a> •
|
|
11
|
+
<a href="docs/i18n/README.zh-CN.md">🇨🇳 简体中文</a> •
|
|
12
|
+
<a href="docs/i18n/README.ko.md">🇰🇷 한국어</a> •
|
|
13
|
+
<a href="docs/i18n/README.pt-BR.md">🇧🇷 Português</a> •
|
|
14
|
+
<a href="docs/i18n/README.ru.md">🇷🇺 Русский</a> •
|
|
15
|
+
<a href="docs/i18n/README.tr.md">🇹🇷 Türkçe</a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
> 💡 **Translation Note:** Help improve translations by opening a PR. The English README is the source of truth.
|
|
19
|
+
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
1
24
|
<!-- HERO START -->
|
|
2
25
|
|
|
3
26
|
<p align="center">
|
|
@@ -14,21 +37,33 @@
|
|
|
14
37
|
<a href="https://bytes.dev/archives/429"><img alt="Featured in Bytes #429" src="https://img.shields.io/badge/featured-Bytes%20%23429-111111"></a>
|
|
15
38
|
<a href="https://dev.to/sonotommy/secure-nodejs-file-uploads-in-minutes-with-pompelmi-3jfe"><img alt="Featured on DEV.to" src="https://img.shields.io/badge/featured-DEV.to-0A0A0A?logo=devdotto"></a>
|
|
16
39
|
<br/>
|
|
40
|
+
<a href="https://github.com/sorrycc/awesome-javascript"><img alt="Mentioned in Awesome JavaScript" src="https://awesome.re/mentioned-badge.svg"></a>
|
|
41
|
+
<a href="https://github.com/dzharii/awesome-typescript"><img alt="Mentioned in Awesome TypeScript" src="https://awesome.re/mentioned-badge-flat.svg"></a>
|
|
42
|
+
<br/>
|
|
17
43
|
|
|
18
44
|
</p>
|
|
19
45
|
|
|
20
46
|
<h1 align="center">pompelmi</h1>
|
|
21
47
|
|
|
48
|
+
<p align="center">
|
|
49
|
+
<strong>Fast, Private, and Powerful File Malware Scanning for Node.js</strong>
|
|
50
|
+
</p>
|
|
22
51
|
|
|
52
|
+
<p align="center">
|
|
53
|
+
⚡ Zero-config setup • 🔒 Privacy-first • 🧩 Composable scanners • 📦 Deep ZIP inspection • 🎯 Framework adapters
|
|
54
|
+
</p>
|
|
23
55
|
|
|
24
56
|
<p align="center">
|
|
57
|
+
<strong>YARA</strong> integration • <strong>ZIP bomb</strong> protection • Drop-in middleware for <strong>Express</strong>, <strong>Koa</strong>, <strong>NestJS</strong>, <strong>Fastify</strong>, and <strong>Next.js</strong> • <strong>CLI</strong> for CI/CD
|
|
58
|
+
</p>
|
|
25
59
|
|
|
26
|
-
<
|
|
60
|
+
<p align="center">
|
|
61
|
+
<em>Scan files before they hit disk. Keep user data private. Ship with confidence.</em>
|
|
27
62
|
</p>
|
|
28
63
|
|
|
29
64
|
**Keywords:** file upload security · malware detection · YARA · Node.js middleware · Express · Koa · Next.js · ZIP bomb protection
|
|
30
65
|
|
|
31
|
-
|
|
66
|
+
---
|
|
32
67
|
|
|
33
68
|
<p align="center">
|
|
34
69
|
<a href="https://www.npmjs.com/package/pompelmi"><img alt="npm version" src="https://img.shields.io/npm/v/pompelmi?label=version&color=0a7ea4&logo=npm"></a>
|
|
@@ -39,6 +74,13 @@
|
|
|
39
74
|
<a href="https://snyk.io/test/github/pompelmi/pompelmi"><img alt="Known Vulnerabilities" src="https://snyk.io/test/github/pompelmi/pompelmi/badge.svg"></a>
|
|
40
75
|
</p>
|
|
41
76
|
|
|
77
|
+
<p align="center">
|
|
78
|
+
<a href="https://www.npmjs.com/package/@pompelmi/cli"><img alt="CLI version" src="https://img.shields.io/npm/v/@pompelmi/cli?label=CLI&color=0a7ea4&logo=npm"></a>
|
|
79
|
+
<a href="https://www.npmjs.com/package/@pompelmi/nestjs-integration"><img alt="NestJS version" src="https://img.shields.io/npm/v/@pompelmi/nestjs-integration?label=NestJS&color=E0234E&logo=nestjs"></a>
|
|
80
|
+
<a href="https://www.npmjs.com/package/@pompelmi/express-middleware"><img alt="Express version" src="https://img.shields.io/npm/v/@pompelmi/express-middleware?label=Express&color=000000&logo=express"></a>
|
|
81
|
+
<a href="https://www.npmjs.com/package/@pompelmi/next-upload"><img alt="Next.js version" src="https://img.shields.io/npm/v/@pompelmi/next-upload?label=Next.js&color=000000&logo=nextdotjs"></a>
|
|
82
|
+
</p>
|
|
83
|
+
|
|
42
84
|
<p align="center">
|
|
43
85
|
<img alt="node" src="https://img.shields.io/badge/node-%3E%3D18-339933?logo=node.js&logoColor=white">
|
|
44
86
|
<img alt="types" src="https://img.shields.io/badge/types-TypeScript-3178C6?logo=typescript&logoColor=white">
|
|
@@ -108,8 +150,12 @@
|
|
|
108
150
|
- [Express](#express)
|
|
109
151
|
- [Koa](#koa)
|
|
110
152
|
- [Next.js (App Router)](#nextjs-app-router)
|
|
153
|
+
- [Adapters](#adapters)
|
|
154
|
+
- [GitHub Action](#github-action)
|
|
111
155
|
- [Configuration](#configuration)
|
|
156
|
+
- [YARA Getting Started](#yara-getting-started)
|
|
112
157
|
- [Security Notes](#security-notes)
|
|
158
|
+
|
|
113
159
|
- [Testing & Development](#testing--development)
|
|
114
160
|
- [FAQ](#faq)
|
|
115
161
|
- [Contributing](#contributing)
|
|
@@ -117,6 +163,25 @@
|
|
|
117
163
|
|
|
118
164
|
---
|
|
119
165
|
|
|
166
|
+
## 🌍 Translations
|
|
167
|
+
|
|
168
|
+
pompelmi documentation is available in multiple languages to help developers worldwide:
|
|
169
|
+
|
|
170
|
+
- 🇮🇹 **[Italiano (Italian)](docs/i18n/README.it.md)** — Documentazione completa in italiano
|
|
171
|
+
- 🇫🇷 **[Français (French)](docs/i18n/README.fr.md)** — Documentation complète en français
|
|
172
|
+
- 🇪🇸 **[Español (Spanish)](docs/i18n/README.es.md)** — Documentación completa en español
|
|
173
|
+
- 🇩🇪 **[Deutsch (German)](docs/i18n/README.de.md)** — Vollständige Dokumentation auf Deutsch
|
|
174
|
+
- 🇯🇵 **[日本語 (Japanese)](docs/i18n/README.ja.md)** — 日本語による完全なドキュメント
|
|
175
|
+
- 🇨🇳 **[简体中文 (Simplified Chinese)](docs/i18n/README.zh-CN.md)** — 完整的简体中文文档
|
|
176
|
+
- 🇰🇷 **[한국어 (Korean)](docs/i18n/README.ko.md)** — 완전한 한국어 문서
|
|
177
|
+
- 🇧🇷 **[Português (Brasil)](docs/i18n/README.pt-BR.md)** — Documentação completa em português
|
|
178
|
+
- 🇷🇺 **[Русский (Russian)](docs/i18n/README.ru.md)** — Полная документация на русском
|
|
179
|
+
- 🇹🇷 **[Türkçe (Turkish)](docs/i18n/README.tr.md)** — Türkçe tam dokümantasyon
|
|
180
|
+
|
|
181
|
+
**Help improve translations:** We welcome contributions to improve and maintain translations. The English README is the authoritative source. To contribute, please open a Pull Request with your improvements.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
120
185
|
## 🚀 Overview
|
|
121
186
|
|
|
122
187
|
**pompelmi** scans untrusted file uploads **before** they hit disk. A tiny, TypeScript-first toolkit for Node.js with composable scanners, deep ZIP inspection, and optional signature engines.
|
|
@@ -129,7 +194,13 @@
|
|
|
129
194
|
|
|
130
195
|
**📦 ZIP hardening** — traversal/bomb guards, polyglot & macro hints
|
|
131
196
|
|
|
132
|
-
**🔌 Drop-in adapters** — Express, Koa, Fastify, Next.js
|
|
197
|
+
**🔌 Drop-in adapters** — Express, Koa, Fastify, Next.js, **NestJS**
|
|
198
|
+
|
|
199
|
+
**🌊 Stream-based scanning** — memory-efficient processing with configurable buffer limits
|
|
200
|
+
|
|
201
|
+
**⚙️ CLI for CI/CD** — standalone command-line tool for scanning files and directories
|
|
202
|
+
|
|
203
|
+
**🔍 Polyglot detection** — advanced magic bytes analysis and embedded script detection
|
|
133
204
|
|
|
134
205
|
**📘 Typed & tiny** — modern TS, minimal surface, tree-shakeable
|
|
135
206
|
|
|
@@ -143,8 +214,16 @@
|
|
|
143
214
|
|
|
144
215
|
**🔍 Built‑in scanners** — drop‑in **CommonHeuristicsScanner** (PDF risky actions, Office macros, PE header) and **Zip‑bomb Guard**; add your own or YARA via a tiny `{ scan(bytes) }` contract.
|
|
145
216
|
|
|
217
|
+
**🔬 Polyglot & embedded script detection** — advanced magic bytes analysis detects mixed-format files and embedded scripts with **30+ file signatures**.
|
|
218
|
+
|
|
219
|
+
**🌊 Memory-efficient streaming** — scan large files without loading them entirely into memory with automatic stream routing.
|
|
220
|
+
|
|
146
221
|
**⚙️ Compose scanning** — run multiple scanners in parallel or sequentially with timeouts and short‑circuiting via `composeScanners()`.
|
|
147
222
|
|
|
223
|
+
**🏗️ Framework integrations** — native modules for **NestJS**, Express, Koa, Next.js, and Fastify with first-class TypeScript support.
|
|
224
|
+
|
|
225
|
+
**🔧 Production-ready CLI** — standalone tool for CI/CD pipelines with watch mode, multiple output formats (JSON, table, minimal).
|
|
226
|
+
|
|
148
227
|
**☁️ Zero cloud** — scans run in‑process. Keep bytes private. Perfect for GDPR/HIPAA compliance.
|
|
149
228
|
|
|
150
229
|
**👨💻 DX first** — TypeScript types, ESM/CJS builds, tiny API, adapters for popular web frameworks.
|
|
@@ -180,7 +259,6 @@
|
|
|
180
259
|
\* You can run YARA alongside ClamAV, but it’s not built‑in.
|
|
181
260
|
|
|
182
261
|
---
|
|
183
|
-
|
|
184
262
|
## 💬 What Developers Say
|
|
185
263
|
|
|
186
264
|
> "pompelmi made it incredibly easy to add malware scanning to our Express API. The TypeScript support is fantastic!"
|
|
@@ -232,10 +310,6 @@ Validate customer document uploads (ID verification, tax forms) without exposing
|
|
|
232
310
|
|
|
233
311
|
Protect learning management systems from malicious file uploads while maintaining student privacy.
|
|
234
312
|
|
|
235
|
-
### 📱 SaaS Applications
|
|
236
|
-
|
|
237
|
-
Add secure file upload capabilities to your multi-tenant platform with per-tenant policy customization.
|
|
238
|
-
|
|
239
313
|
### 🏢 Enterprise Document Management
|
|
240
314
|
|
|
241
315
|
Scan files at ingestion time for corporate file sharing platforms, wikis, and collaboration tools.
|
|
@@ -248,6 +322,13 @@ Validate user-generated content uploads (images, videos, documents) before proce
|
|
|
248
322
|
|
|
249
323
|
## 🔧 Installation
|
|
250
324
|
|
|
325
|
+
**pompelmi** is a privacy-first Node.js library for local file scanning.
|
|
326
|
+
|
|
327
|
+
**Requirements:**
|
|
328
|
+
- Node.js 18+
|
|
329
|
+
- Optional: ClamAV binaries (for signature-based scanning)
|
|
330
|
+
- Optional: YARA libraries (for custom rules)
|
|
331
|
+
|
|
251
332
|
<table>
|
|
252
333
|
<tr>
|
|
253
334
|
<td><b>npm</b></td>
|
|
@@ -267,7 +348,7 @@ Validate user-generated content uploads (images, videos, documents) before proce
|
|
|
267
348
|
</tr>
|
|
268
349
|
</table>
|
|
269
350
|
|
|
270
|
-
|
|
351
|
+
#### 📦 Optional Framework Adapters
|
|
271
352
|
|
|
272
353
|
```bash
|
|
273
354
|
# Express
|
|
@@ -279,8 +360,14 @@ npm i @pompelmi/koa-middleware
|
|
|
279
360
|
# Next.js
|
|
280
361
|
npm i @pompelmi/next-upload
|
|
281
362
|
|
|
363
|
+
# NestJS
|
|
364
|
+
npm i @pompelmi/nestjs-integration
|
|
365
|
+
|
|
282
366
|
# Fastify (alpha)
|
|
283
367
|
npm i @pompelmi/fastify-plugin
|
|
368
|
+
|
|
369
|
+
# Standalone CLI
|
|
370
|
+
npm i -g @pompelmi/cli
|
|
284
371
|
```
|
|
285
372
|
|
|
286
373
|
> **Note:** Core library works standalone. Install adapters only if using specific frameworks.
|
|
@@ -388,6 +475,67 @@ export const dynamic = 'force-dynamic';
|
|
|
388
475
|
export const POST = createNextUploadHandler({ ...policy, scanner });
|
|
389
476
|
```
|
|
390
477
|
|
|
478
|
+
### NestJS
|
|
479
|
+
|
|
480
|
+
```ts
|
|
481
|
+
// app.module.ts
|
|
482
|
+
import { Module } from '@nestjs/common';
|
|
483
|
+
import { PompelmiModule } from '@pompelmi/nestjs-integration';
|
|
484
|
+
import { CommonHeuristicsScanner } from 'pompelmi';
|
|
485
|
+
|
|
486
|
+
@Module({
|
|
487
|
+
imports: [
|
|
488
|
+
PompelmiModule.forRoot({
|
|
489
|
+
includeExtensions: ['pdf', 'zip', 'png', 'jpg'],
|
|
490
|
+
allowedMimeTypes: ['application/pdf', 'application/zip', 'image/png', 'image/jpeg'],
|
|
491
|
+
maxFileSizeBytes: 10 * 1024 * 1024,
|
|
492
|
+
scanners: [CommonHeuristicsScanner],
|
|
493
|
+
}),
|
|
494
|
+
],
|
|
495
|
+
})
|
|
496
|
+
export class AppModule {}
|
|
497
|
+
|
|
498
|
+
// upload.controller.ts
|
|
499
|
+
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
|
|
500
|
+
import { FileInterceptor } from '@nestjs/platform-express';
|
|
501
|
+
import { PompelmiInterceptor, PompelmiResult } from '@pompelmi/nestjs-integration';
|
|
502
|
+
|
|
503
|
+
@Controller('upload')
|
|
504
|
+
export class UploadController {
|
|
505
|
+
@Post()
|
|
506
|
+
@UseInterceptors(FileInterceptor('file'), PompelmiInterceptor)
|
|
507
|
+
async uploadFile(@UploadedFile() file: Express.Multer.File & { pompelmi?: PompelmiResult }) {
|
|
508
|
+
return {
|
|
509
|
+
success: true,
|
|
510
|
+
verdict: file.pompelmi?.verdict
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
> See `packages/nestjs-integration/README.md` for full documentation.
|
|
517
|
+
|
|
518
|
+
### CLI Usage
|
|
519
|
+
|
|
520
|
+
```bash
|
|
521
|
+
# Scan a single file
|
|
522
|
+
pompelmi scan file.pdf
|
|
523
|
+
|
|
524
|
+
# Scan directory recursively
|
|
525
|
+
pompelmi scan ./uploads --recursive
|
|
526
|
+
|
|
527
|
+
# Watch directory for changes
|
|
528
|
+
pompelmi watch ./uploads
|
|
529
|
+
|
|
530
|
+
# JSON output for CI/CD
|
|
531
|
+
pompelmi scan ./dist --output json --exit-on-suspicious
|
|
532
|
+
|
|
533
|
+
# Full options
|
|
534
|
+
pompelmi scan --help
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
> See `packages/cli/README.md` for comprehensive CLI documentation.
|
|
538
|
+
|
|
391
539
|
---
|
|
392
540
|
|
|
393
541
|
## 🤖 GitHub Action
|
|
@@ -787,9 +935,7 @@ You should see an HTTP **422 Unprocessable Entity** (blocked by policy). Clean f
|
|
|
787
935
|
|
|
788
936
|
---
|
|
789
937
|
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
## 🔔 Releases & security
|
|
938
|
+
## Releases & security
|
|
793
939
|
|
|
794
940
|
- **Changelog / releases:** see [GitHub Releases](https://github.com/pompelmi/pompelmi/releases).
|
|
795
941
|
- **Security disclosures:** please use [GitHub Security Advisories](https://github.com/pompelmi/pompelmi/security/advisories). We’ll coordinate a fix before public disclosure.
|
package/dist/pompelmi.cjs
CHANGED
|
@@ -54,9 +54,10 @@ function createPresetScanner(preset, opts = {}) {
|
|
|
54
54
|
opts.decompilationDepth || 'basic';
|
|
55
55
|
if (!opts.decompilationEngine || opts.decompilationEngine === 'binaryninja-hlil' || opts.decompilationEngine === 'both') {
|
|
56
56
|
try {
|
|
57
|
-
// Dynamic import to avoid bundling issues
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
// Dynamic import to avoid bundling issues - using Function to bypass TypeScript type checking
|
|
58
|
+
const importModule = new Function('specifier', 'return import(specifier)');
|
|
59
|
+
importModule('@pompelmi/engine-binaryninja').then((mod) => {
|
|
60
|
+
const binjaScanner = mod.createBinaryNinjaScanner({
|
|
60
61
|
timeout: opts.decompilationTimeout || opts.timeout || 30000,
|
|
61
62
|
depth,
|
|
62
63
|
pythonPath: opts.pythonPath,
|
|
@@ -73,9 +74,10 @@ function createPresetScanner(preset, opts = {}) {
|
|
|
73
74
|
}
|
|
74
75
|
if (!opts.decompilationEngine || opts.decompilationEngine === 'ghidra-pcode' || opts.decompilationEngine === 'both') {
|
|
75
76
|
try {
|
|
76
|
-
// Dynamic import for Ghidra engine (when implemented)
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
// Dynamic import for Ghidra engine (when implemented) - using Function to bypass TypeScript type checking
|
|
78
|
+
const importModule = new Function('specifier', 'return import(specifier)');
|
|
79
|
+
importModule('@pompelmi/engine-ghidra').then((mod) => {
|
|
80
|
+
const ghidraScanner = mod.createGhidraScanner({
|
|
79
81
|
timeout: opts.decompilationTimeout || opts.timeout || 30000,
|
|
80
82
|
depth,
|
|
81
83
|
ghidraPath: opts.ghidraPath,
|
|
@@ -2272,13 +2274,13 @@ class HipaaComplianceManager {
|
|
|
2272
2274
|
constructor(config) {
|
|
2273
2275
|
this.auditEvents = [];
|
|
2274
2276
|
this.config = {
|
|
2275
|
-
enabled: true,
|
|
2276
2277
|
sanitizeErrors: true,
|
|
2277
2278
|
sanitizeFilenames: true,
|
|
2278
2279
|
encryptTempFiles: true,
|
|
2279
2280
|
memoryProtection: true,
|
|
2280
2281
|
requireSecureTransport: true,
|
|
2281
|
-
...config
|
|
2282
|
+
...config,
|
|
2283
|
+
enabled: config.enabled !== undefined ? config.enabled : true
|
|
2282
2284
|
};
|
|
2283
2285
|
this.sessionId = this.generateSessionId();
|
|
2284
2286
|
}
|