pompelmi 0.35.1 → 0.35.3
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 +108 -114
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,162 +1,152 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<img src="assets/logo.svg" alt="Pompelmi logo" width="
|
|
3
|
-
|
|
4
|
-
<
|
|
2
|
+
<img src="./assets/logo.svg" alt="Pompelmi logo" width="144" />
|
|
3
|
+
|
|
4
|
+
<h1>Pompelmi</h1>
|
|
5
|
+
|
|
6
|
+
<p><strong>Route-level upload security for Node.js.</strong></p>
|
|
7
|
+
|
|
8
|
+
<p>Inspect untrusted uploads before storage.</p>
|
|
9
|
+
|
|
5
10
|
<p>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
<a href="https://codecov.io/gh/pompelmi/pompelmi"><img alt="Codecov" src="https://codecov.io/gh/pompelmi/pompelmi/branch/main/graph/badge.svg?flag=core"></a>
|
|
9
|
-
<a href="https://github.com/pompelmi/pompelmi/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/pompelmi/pompelmi"></a>
|
|
10
|
-
<a href="https://www.npmjs.com/package/pompelmi"><img alt="npm downloads" src="https://img.shields.io/npm/dm/pompelmi"></a>
|
|
11
|
+
MIME and extension spoofing · archive abuse · risky document and binary
|
|
12
|
+
signals · optional YARA
|
|
11
13
|
</p>
|
|
14
|
+
|
|
15
|
+
<p><code>clean</code> · <code>suspicious</code> · <code>malicious</code></p>
|
|
16
|
+
|
|
12
17
|
<p>
|
|
13
|
-
<
|
|
14
|
-
<a href="https://github.com/dzharii/awesome-typescript"><img alt="Mentioned in Awesome TypeScript" src="https://img.shields.io/badge/mentioned-Awesome%20TypeScript-3178C6"></a>
|
|
15
|
-
<a href="https://nodeweekly.com/issues/594"><img alt="Featured in Node Weekly #594" src="https://img.shields.io/badge/featured-Node%20Weekly%20%23594-339933?logo=node.js&logoColor=white"></a>
|
|
16
|
-
<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>
|
|
18
|
+
<sub>Express · Next.js · NestJS · Fastify · Koa · Nuxt/Nitro · S3 quarantine flows · CI/CD</sub>
|
|
17
19
|
</p>
|
|
20
|
+
|
|
21
|
+
<p><sub>Open-source core · MIT · Node.js 18+</sub></p>
|
|
22
|
+
|
|
18
23
|
<p>
|
|
19
|
-
<a href="https://www.
|
|
20
|
-
<a href="https://
|
|
21
|
-
<a href="https://
|
|
22
|
-
<a href="https://
|
|
24
|
+
<a href="https://www.npmjs.com/package/pompelmi"><img alt="npm version" src="https://img.shields.io/npm/v/pompelmi" /></a>
|
|
25
|
+
<a href="https://github.com/pompelmi/pompelmi/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/pompelmi/pompelmi/ci.yml?label=ci" /></a>
|
|
26
|
+
<a href="https://codecov.io/gh/pompelmi/pompelmi"><img alt="codecov" src="https://codecov.io/gh/pompelmi/pompelmi/graph/badge.svg" /></a>
|
|
27
|
+
<a href="https://github.com/pompelmi/pompelmi/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/pompelmi/pompelmi?style=social" /></a>
|
|
28
|
+
<a href="https://www.npmjs.com/package/pompelmi"><img alt="npm weekly downloads" src="https://img.shields.io/npm/dw/pompelmi" /></a>
|
|
29
|
+
<a href="https://www.npmjs.com/package/pompelmi"><img alt="npm monthly downloads" src="https://img.shields.io/npm/dm/pompelmi" /></a>
|
|
23
30
|
</p>
|
|
24
|
-
</div>
|
|
25
31
|
|
|
26
|
-
>
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
<p>
|
|
33
|
+
<a href="https://pompelmi.github.io/pompelmi/getting-started/"><strong>Getting started</strong></a>
|
|
34
|
+
·
|
|
35
|
+
<a href="https://pompelmi.github.io/pompelmi/#browser-preview"><strong>Browser preview</strong></a>
|
|
36
|
+
·
|
|
37
|
+
<a href="./examples/demo"><strong>Express demo</strong></a>
|
|
38
|
+
·
|
|
39
|
+
<a href="./examples/README.md"><strong>Examples</strong></a>
|
|
40
|
+
</p>
|
|
41
|
+
</div>
|
|
29
42
|
|
|
30
|
-
|
|
43
|
+
<p align="center">
|
|
44
|
+
Mentioned by <a href="https://nodeweekly.com/issues/594">Node Weekly</a>,
|
|
45
|
+
<a href="https://stackoverflow.blog/2026/02/23/defense-against-uploads-oss-file-scanner-pompelmi/">Stack Overflow</a>,
|
|
46
|
+
<a href="https://www.helpnetsecurity.com/2026/02/02/pompelmi-open-source-secure-file-upload-scanning-node-js/">Help Net Security</a>,
|
|
47
|
+
<a href="https://github.com/sorrycc/awesome-javascript">Awesome JavaScript</a>,
|
|
48
|
+
and
|
|
49
|
+
<a href="https://github.com/dzharii/awesome-typescript">Awesome TypeScript</a>.
|
|
50
|
+
</p>
|
|
31
51
|
|
|
32
|
-
|
|
52
|
+
## Quick Start
|
|
33
53
|
|
|
34
|
-
|
|
54
|
+
Install the core package:
|
|
35
55
|
|
|
36
56
|
```bash
|
|
37
57
|
npm install pompelmi
|
|
38
58
|
```
|
|
39
59
|
|
|
40
|
-
|
|
60
|
+
Minimal route-level example:
|
|
41
61
|
|
|
42
|
-
|
|
62
|
+
```ts
|
|
63
|
+
import { scanBytes, STRICT_PUBLIC_UPLOAD } from 'pompelmi';
|
|
43
64
|
|
|
44
|
-
|
|
65
|
+
const report = await scanBytes(req.file.buffer, {
|
|
66
|
+
filename: req.file.originalname,
|
|
67
|
+
mimeType: req.file.mimetype,
|
|
68
|
+
policy: STRICT_PUBLIC_UPLOAD,
|
|
69
|
+
failClosed: true,
|
|
70
|
+
});
|
|
45
71
|
|
|
46
|
-
|
|
47
|
-
|
|
72
|
+
if (report.verdict !== 'clean') {
|
|
73
|
+
return res.status(422).json({
|
|
74
|
+
error: 'Upload blocked',
|
|
75
|
+
verdict: report.verdict,
|
|
76
|
+
reasons: report.reasons,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return res.status(200).json({ verdict: report.verdict });
|
|
48
81
|
```
|
|
49
82
|
|
|
50
|
-
|
|
83
|
+
Start with [Getting started](https://pompelmi.github.io/pompelmi/getting-started/) for a local scan in under a minute, open the [browser preview](https://pompelmi.github.io/pompelmi/#browser-preview) to inspect the verdict flow without sending files anywhere, or run the minimal [Express demo](./examples/demo).
|
|
51
84
|
|
|
52
|
-
|
|
53
|
-
import { scanBytes } from "pompelmi";
|
|
54
|
-
import { readFileSync } from "node:fs";
|
|
85
|
+
If Pompelmi matches how you want upload security to work, star the repo so more Node.js teams can find it.
|
|
55
86
|
|
|
56
|
-
|
|
87
|
+
## Why It Exists
|
|
57
88
|
|
|
58
|
-
|
|
59
|
-
filename: "package.json",
|
|
60
|
-
mimeType: "application/json",
|
|
61
|
-
});
|
|
89
|
+
Upload endpoints are part of your attack surface. A file can look harmless at the form layer and become dangerous only after storage, extraction, rendering, or downstream parsing.
|
|
62
90
|
|
|
63
|
-
|
|
64
|
-
console.log("Reasons:", report.reasons);
|
|
65
|
-
console.log("Duration:", report.durationMs, "ms");
|
|
66
|
-
```
|
|
91
|
+
Pompelmi keeps the first decision inside the application path, where the route still knows the file class, trust level, storage path, and failure mode.
|
|
67
92
|
|
|
68
|
-
|
|
93
|
+
## What It Checks
|
|
69
94
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
95
|
+
- MIME sniffing, magic-byte validation, and extension allowlists
|
|
96
|
+
- risky archive structures such as traversal, deep nesting, entry-count abuse, and ZIP bomb-style expansion
|
|
97
|
+
- suspicious document and binary signals such as risky PDF actions, Office macro hints, PE headers, and polyglot files
|
|
98
|
+
- optional YARA or other scanner matches
|
|
99
|
+
- route-level verdicts that support reject, quarantine, or promote workflows
|
|
73
100
|
|
|
74
|
-
|
|
101
|
+
## Where It Fits
|
|
75
102
|
|
|
76
|
-
|
|
103
|
+
- public or semi-trusted upload endpoints that should inspect first and store later
|
|
104
|
+
- memory-backed multipart routes in Express, Next.js, NestJS, Fastify, and Koa
|
|
105
|
+
- quarantine and promotion workflows for S3 or other object storage
|
|
106
|
+
- document, image, and archive routes that need different policies
|
|
107
|
+
- CI/CD or internal artifact scanning before promotion
|
|
77
108
|
|
|
78
|
-
|
|
79
|
-
import { scanBytes, STRICT_PUBLIC_UPLOAD } from "pompelmi";
|
|
109
|
+
## Why Not Just X?
|
|
80
110
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (report.verdict !== "clean") {
|
|
89
|
-
return res.status(422).json({
|
|
90
|
-
error: "Upload blocked",
|
|
91
|
-
verdict: report.verdict,
|
|
92
|
-
reasons: report.reasons,
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
```
|
|
111
|
+
| Approach | Useful for | What it misses |
|
|
112
|
+
| --- | --- | --- |
|
|
113
|
+
| Browser MIME and extension checks | Fast client-side hints and UX feedback | Filenames and client-reported MIME are easy to spoof |
|
|
114
|
+
| Simple file-type or magic-byte checks | Confirming the file appears to be the claimed type | Risky internal structure, archive abuse, and route policy decisions |
|
|
115
|
+
| Antivirus-only thinking | Known malicious matches and signature-based detection | Route context, spoofing checks, storage decisions, and non-signature risk signals |
|
|
116
|
+
| Pompelmi at the upload route | Inspect-first, store-later decisions with policy, structure checks, and optional YARA | It is not a full antivirus replacement on its own |
|
|
96
117
|
|
|
97
|
-
##
|
|
118
|
+
## Integrations
|
|
98
119
|
|
|
99
|
-
- Express: [Docs](https://pompelmi.github.io/pompelmi/how-to/express/) · [
|
|
100
|
-
- Next.js: [Docs](https://pompelmi.github.io/pompelmi/how-to/nextjs/) · [
|
|
120
|
+
- Express: [Docs](https://pompelmi.github.io/pompelmi/how-to/express/) · [Minimal example](./examples/express-minimal) · [Demo](./examples/demo)
|
|
121
|
+
- Next.js: [Docs](https://pompelmi.github.io/pompelmi/how-to/nextjs/) · [Example](./examples/next-app-router)
|
|
101
122
|
- NestJS: [Docs](https://pompelmi.github.io/pompelmi/how-to/nestjs/) · [Example app](./examples/nestjs-app)
|
|
102
123
|
- Fastify: [Docs](https://pompelmi.github.io/pompelmi/how-to/fastify/) · [Package](./packages/fastify-plugin)
|
|
103
124
|
- Koa: [Docs](https://pompelmi.github.io/pompelmi/how-to/koa/) · [Package](./packages/koa-middleware)
|
|
104
|
-
-
|
|
125
|
+
- Nuxt/Nitro: [Docs](https://pompelmi.github.io/pompelmi/how-to/nuxt-nitro/)
|
|
105
126
|
- S3 / object storage: [Tutorial](https://pompelmi.github.io/pompelmi/tutorials/secure-s3-presigned-uploads-with-malware-scanning/) · [Use case](https://pompelmi.github.io/pompelmi/use-cases/s3-presigned-upload-security/)
|
|
127
|
+
- CI/CD: [Use case](https://pompelmi.github.io/pompelmi/use-cases/cicd-artifact-scanning/) · [Blog](https://pompelmi.github.io/pompelmi/blog/cicd-scan-build-artifacts/)
|
|
128
|
+
|
|
129
|
+
## Demo, Preview, and Examples
|
|
106
130
|
|
|
107
|
-
|
|
131
|
+

|
|
132
|
+
|
|
133
|
+
- [Browser preview](https://pompelmi.github.io/pompelmi/#browser-preview) for a fast local evaluation of the verdict UX
|
|
134
|
+
- [Demo](./examples/demo) for a tiny Express upload gate that returns `clean`, `suspicious`, or `malicious` before storage
|
|
135
|
+
- [Examples index](./examples/README.md) for framework-specific and production-oriented examples
|
|
136
|
+
|
|
137
|
+
## Docs
|
|
108
138
|
|
|
109
139
|
- [Docs home](https://pompelmi.github.io/pompelmi/)
|
|
140
|
+
- [Getting started](https://pompelmi.github.io/pompelmi/getting-started/)
|
|
110
141
|
- [Use cases](https://pompelmi.github.io/pompelmi/use-cases/)
|
|
111
142
|
- [Comparisons](https://pompelmi.github.io/pompelmi/comparisons/)
|
|
112
143
|
- [Tutorials](https://pompelmi.github.io/pompelmi/tutorials/)
|
|
113
144
|
- [Featured in](https://pompelmi.github.io/pompelmi/featured-in/)
|
|
114
145
|
- [Translations](https://pompelmi.github.io/pompelmi/translations/)
|
|
115
|
-
- [Examples index](./examples/README.md)
|
|
116
|
-
- [Demo example](./examples/demo)
|
|
117
|
-
- [Contributing](./CONTRIBUTING.md)
|
|
118
|
-
- [Security](./SECURITY.md)
|
|
119
|
-
- [Roadmap](./ROADMAP.md)
|
|
120
|
-
|
|
121
|
-
## What It Checks
|
|
122
|
-
|
|
123
|
-
Upload endpoints are part of your attack surface. A renamed executable, a risky PDF, or a hostile archive can look harmless until it is stored, unpacked, served, or parsed by another system.
|
|
124
|
-
|
|
125
|
-
Pompelmi adds checks at the upload boundary for:
|
|
126
|
-
|
|
127
|
-
- MIME spoofing and magic-byte mismatches
|
|
128
|
-
- Archive abuse such as ZIP bombs, traversal, and deep nesting
|
|
129
|
-
- Polyglot files and risky document structures
|
|
130
|
-
- Optional YARA-based signature matching
|
|
131
|
-
|
|
132
|
-
The goal is simple: inspect first, store later.
|
|
133
|
-
|
|
134
|
-
## Ecosystem
|
|
135
146
|
|
|
136
|
-
|
|
137
|
-
- `@pompelmi/express-middleware`
|
|
138
|
-
- `@pompelmi/koa-middleware`
|
|
139
|
-
- `@pompelmi/next-upload`
|
|
140
|
-
- `@pompelmi/nestjs-integration`
|
|
141
|
-
- `@pompelmi/fastify-plugin`
|
|
142
|
-
- `@pompelmi/ui-react`
|
|
143
|
-
- `@pompelmi/cli`
|
|
147
|
+
## Enterprise and Commercial Support
|
|
144
148
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
- `src/` core library
|
|
148
|
-
- `packages/` framework adapters and supporting packages
|
|
149
|
-
- `examples/` runnable examples
|
|
150
|
-
- `tests/` test coverage
|
|
151
|
-
- `website/` public docs, blog, and discovery site
|
|
152
|
-
|
|
153
|
-
## Development
|
|
154
|
-
|
|
155
|
-
```bash
|
|
156
|
-
pnpm install
|
|
157
|
-
pnpm test
|
|
158
|
-
pnpm build
|
|
159
|
-
```
|
|
149
|
+
The MIT core remains the primary path. Teams that need private rollout help, architecture review, or policy tuning can use the existing [enterprise support path](https://pompelmi.github.io/pompelmi/enterprise/).
|
|
160
150
|
|
|
161
151
|
<!-- MENTIONS:START -->
|
|
162
152
|
|
|
@@ -189,6 +179,10 @@ Full page: [pompelmi.github.io/pompelmi/featured-in](https://pompelmi.github.io/
|
|
|
189
179
|
|
|
190
180
|
<!-- MENTIONS:END -->
|
|
191
181
|
|
|
192
|
-
##
|
|
182
|
+
## Project
|
|
193
183
|
|
|
194
|
-
[
|
|
184
|
+
- [Contributing](./CONTRIBUTING.md)
|
|
185
|
+
- [Security](./SECURITY.md)
|
|
186
|
+
- [Roadmap](./ROADMAP.md)
|
|
187
|
+
- [GitHub Discussions](https://github.com/pompelmi/pompelmi/discussions)
|
|
188
|
+
- [License](./LICENSE)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pompelmi",
|
|
3
|
-
"version": "0.35.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.35.3",
|
|
4
|
+
"description": "Inspect untrusted uploads before storage in Node.js. Open-source upload security with checks for spoofing, archive abuse, risky document and binary signals, and optional YARA.",
|
|
5
5
|
"main": "./dist/pompelmi.cjs",
|
|
6
6
|
"module": "./dist/pompelmi.esm.js",
|
|
7
7
|
"type": "module",
|