mitigator 1.0.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/LICENSE.md +15 -0
- package/README.md +355 -0
- package/dist/bin/mitigator-audit.cjs +187 -0
- package/dist/bin/mitigator-audit.cjs.map +1 -0
- package/dist/bin/mitigator-audit.d.cts +14 -0
- package/dist/bin/mitigator-audit.d.ts +14 -0
- package/dist/bin/mitigator-audit.js +135 -0
- package/dist/bin/mitigator-audit.js.map +1 -0
- package/dist/chunk-TT2DUALY.js +123 -0
- package/dist/chunk-TT2DUALY.js.map +1 -0
- package/dist/index.cjs +1643 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1116 -0
- package/dist/index.d.ts +1116 -0
- package/dist/index.js +1501 -0
- package/dist/index.js.map +1 -0
- package/package.json +86 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Mohamed
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
# Mitigator 🛡️
|
|
2
|
+
|
|
3
|
+
**Mitigator** is a production-grade, security-first TypeScript library designed to eliminate common vulnerabilities and implement advanced defense-in-depth patterns in Node.js applications.
|
|
4
|
+
|
|
5
|
+
Unlike generic utility libraries, Mitigator is built with a "Zero-Trust" philosophy, providing tools specifically hardened against XSS, Prototype Pollution, Path Traversal, SQL Injection, and more.
|
|
6
|
+
|
|
7
|
+
## 🛡️ Mitigated Risks
|
|
8
|
+
|
|
9
|
+
Mitigator provides built-in defenses against the most critical web vulnerabilities, mapping directly to OWASP Top 10 categories:
|
|
10
|
+
|
|
11
|
+
- **Cross-Site Scripting (XSS)**: Automatic HTML escaping and allowlist-based sanitization prevent malicious scripts from executing in the user's browser.
|
|
12
|
+
- **Prototype Pollution**: Strict filtering of `__proto__` and `constructor` keys during JSON parsing and object merging prevents attackers from compromising the Node.js runtime.
|
|
13
|
+
- **Path Traversal (LFI)**: Root-locked path resolution ensures that file system operations cannot escape designated directories.
|
|
14
|
+
- **Injection Attacks**: Heuristic detection of SQL/NoSQL injection patterns and enforcement of parameterized-like query structures.
|
|
15
|
+
- **Broken Authentication**: Protection against credential stuffing via HIBP leak checks and support for modern, phishing-resistant WebAuthn (Passkeys).
|
|
16
|
+
- **Denial of Service (DoS)**: Rate limiting, JSON depth analysis, and circular reference detection prevent resource exhaustion attacks.
|
|
17
|
+
- **Sensitive Data Exposure**: Automated redaction of secrets in logs and secure, encrypted session management (AES-256-GCM).
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## ✨ Key Features
|
|
22
|
+
|
|
23
|
+
- 🛡️ **XSS Protection**: Robust HTML sanitization powered by `sanitize-html` and DOM clobbering prevention.
|
|
24
|
+
- ⚡ **Prototype Pollution Defense**: Secure object merging and safe JSON parsing.
|
|
25
|
+
- 📂 **Path Traversal Mitigation**: Root-locked file system operations.
|
|
26
|
+
- 🔐 **Advanced Auth**: WebAuthn/Passkey verification, JWT signature validation, ZKP challenges, and CSRF protection.
|
|
27
|
+
- 🧬 **Cryptographic Hardening**: AES-256-GCM sessions, strict scrypt hashing.
|
|
28
|
+
- 🚀 **Performance**: CPU-intensive crypto offloaded to Worker Threads.
|
|
29
|
+
- 🚦 **Adaptive Rate Limiting**: Security-aware throttling with Redis cluster support and global kill-switch.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 🚀 Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install mitigator
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
> [!WARNING]
|
|
40
|
+
> **Browser / Edge runtime — `crypto` namespace collision.**
|
|
41
|
+
> The `crypto` named export shadows the browser's built-in `globalThis.crypto` (Web Crypto API)
|
|
42
|
+
> within the importing module's scope. Use a named alias in browser or edge runtimes:
|
|
43
|
+
>
|
|
44
|
+
> ```typescript
|
|
45
|
+
> import { crypto as mitigatorCrypto } from 'mitigator';
|
|
46
|
+
> ```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 📦 Modules Overview
|
|
51
|
+
|
|
52
|
+
| Module | Description |
|
|
53
|
+
| :---------- | :------------------------------------------------------------------------- |
|
|
54
|
+
| `sanitize` | HTML escaping, tag stripping, and robust sanitization (XSS defense). |
|
|
55
|
+
| `validate` | Schema enforcement, secret scanning, and pwned password checks. |
|
|
56
|
+
| `headers` | Security headers (CSP, HSTS, etc.) and strict CSP builders. |
|
|
57
|
+
| `auth` | WebAuthn, HMAC challenge-response, CSRF, JWT validation, and RBAC helpers. |
|
|
58
|
+
| `crypto` | AES session encryption, SSS, and PQC. |
|
|
59
|
+
| `fs` | Secure path resolution and magic number file type verification. |
|
|
60
|
+
| `http` | URL normalization, TLS fingerprinting, and SRI generation. |
|
|
61
|
+
| `rateLimit` | Adaptive rate limiting and Token Bucket implementations. |
|
|
62
|
+
| `safeJson` | DoS-resistant and prototype-pollution safe JSON parsing. |
|
|
63
|
+
| `safeMerge` | Deep merging protected against prototype pollution. |
|
|
64
|
+
| `utils` | Sensitive data redaction, secure error handling, and prototype lockdown. |
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 🛠️ Detailed Usage
|
|
69
|
+
|
|
70
|
+
### 1. Input Sanitization (`sanitize`)
|
|
71
|
+
|
|
72
|
+
Prevent XSS by cleaning untrusted HTML or escaping characters. Backed by `sanitize-html`.
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { sanitize } from 'mitigator';
|
|
76
|
+
|
|
77
|
+
// Basic HTML escaping
|
|
78
|
+
const escaped = sanitize.escapeHtml('<script>alert("xss")</script>');
|
|
79
|
+
|
|
80
|
+
// Robust HTML sanitization with allowlist
|
|
81
|
+
const clean = sanitize.sanitizeHtml('<p>Hello <script>bad()</script> <b>World</b></p>');
|
|
82
|
+
// Output: <p>Hello <b>World</b></p>
|
|
83
|
+
|
|
84
|
+
// Prevent DOM Clobbering by namespacing IDs/Names
|
|
85
|
+
const safeHtml = sanitize.preventDOMClobbering('<img id="config">');
|
|
86
|
+
// Output: <img id="sk-config">
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 2. Secure File Operations (`fs`)
|
|
90
|
+
|
|
91
|
+
Stop path traversal attacks by locking file operations to a root directory.
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { fs } from 'mitigator';
|
|
95
|
+
|
|
96
|
+
const root = './uploads';
|
|
97
|
+
|
|
98
|
+
// This will throw if the path attempts to escape './uploads' (e.g., '../../etc/passwd')
|
|
99
|
+
const safePath = fs.resolveSafePath(root, 'user-data.json');
|
|
100
|
+
|
|
101
|
+
// Verify file type by Magic Numbers (more secure than extension check)
|
|
102
|
+
const isPNG = await fs.verifyMagicNumber('image.bin', fs.MAGIC_NUMBERS.PNG);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 3. Adaptive Rate Limiting (`rateLimit`)
|
|
106
|
+
|
|
107
|
+
Automatically penalize high-risk actors based on security events.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { rateLimit } from 'mitigator';
|
|
111
|
+
|
|
112
|
+
const limiter = new rateLimit.AdaptiveRateLimiter({
|
|
113
|
+
standardLimit: 100,
|
|
114
|
+
penaltyLimit: 10, // Strict limit for suspicious users
|
|
115
|
+
windowMs: 60000, // 1 minute
|
|
116
|
+
securityThreshold: 5, // Max security events before penalty
|
|
117
|
+
burstThreshold: 3, // Max bursts before penalty
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
if (await limiter.isLimited('user-ip')) {
|
|
121
|
+
throw new Error('Too many requests');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Record a suspicious event (e.g., failed login)
|
|
125
|
+
await limiter.recordSecurityEvent('user-ip', 1);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 4. Safe Object Handling (`safeJson` & `safeMerge`)
|
|
129
|
+
|
|
130
|
+
Protect your application from Prototype Pollution.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { safeJson, safeMerge } from 'mitigator';
|
|
134
|
+
|
|
135
|
+
// Parse JSON while stripping __proto__ and constructor keys
|
|
136
|
+
const data = safeJson.parse(untrustedString);
|
|
137
|
+
|
|
138
|
+
// Deep merge objects without risking prototype pollution
|
|
139
|
+
const config = safeMerge.merge(defaultConfig, userConfig);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 5. Advanced Cryptography (`crypto` & `auth`)
|
|
143
|
+
|
|
144
|
+
Implement high-level security and quantum-resistant patterns with ease.
|
|
145
|
+
|
|
146
|
+
#### Shamir's Secret Sharing (SSS)
|
|
147
|
+
|
|
148
|
+
Split sensitive keys into $M$ cryptographic shares where any $T$ shares can exactly reconstruct the original secret, but fewer than $T$ yields only garbage. Built over Galois Field $GF(256)$ with AES primitive polynomial arithmetic.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { crypto } from 'mitigator';
|
|
152
|
+
|
|
153
|
+
// Split secret key into 5 shares with a threshold of 3
|
|
154
|
+
const shares = crypto.splitSecret('master-key-content', 5, 3);
|
|
155
|
+
|
|
156
|
+
// Reconstruct with any 3 shares
|
|
157
|
+
const reconstructed = crypto.reconstructSecret([shares[0], shares[2], shares[4]]);
|
|
158
|
+
console.log(reconstructed.toString('utf8')); // 'master-key-content'
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### Post-Quantum Cryptography (PQC)
|
|
162
|
+
|
|
163
|
+
Phishing-resistant, quantum-resistant one-time signatures powered by the standard **Winternitz One-Time Signatures (WOTS)** nibble-chaining hash framework.
|
|
164
|
+
|
|
165
|
+
> [!CAUTION]
|
|
166
|
+
> **WOTS is a ONE-TIME signature scheme.** Each `privateKey` **must only ever sign a single
|
|
167
|
+
> message**. Signing a second message with the same private key leaks enough key material
|
|
168
|
+
> to forge arbitrary signatures, completely breaking the security of the scheme.
|
|
169
|
+
>
|
|
170
|
+
> **Always generate a fresh key pair with `generatePQCKeyPair()` for every message you sign.**
|
|
171
|
+
> Mitigator enforces this at runtime — `signPQC()` throws `WOTS_KEY_REUSE` if you attempt
|
|
172
|
+
> to reuse a private key within the same process.
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { crypto as mitigatorCrypto } from 'mitigator';
|
|
176
|
+
|
|
177
|
+
// Generate key pair
|
|
178
|
+
const { publicKey, privateKey } = mitigatorCrypto.generatePQCKeyPair();
|
|
179
|
+
|
|
180
|
+
// Sign and verify message — each key pair can only sign ONCE
|
|
181
|
+
const signature = mitigatorCrypto.signPQC('quantum-secure-payload', privateKey);
|
|
182
|
+
const isValid = mitigatorCrypto.verifyPQCSignature('quantum-secure-payload', signature, publicKey); // true
|
|
183
|
+
|
|
184
|
+
// ❌ This will throw WOTS_KEY_REUSE:
|
|
185
|
+
// mitigatorCrypto.signPQC('second message', privateKey);
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
#### HMAC Challenge-Response
|
|
189
|
+
|
|
190
|
+
Server-side mutual authentication using an HMAC challenge-response flow.
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
import { auth } from 'mitigator';
|
|
194
|
+
|
|
195
|
+
const salt = 'per-user-random-salt';
|
|
196
|
+
const challenge = auth.generateHmacChallenge(salt);
|
|
197
|
+
|
|
198
|
+
// Client computes: HMAC-SHA256(secret, challenge) and sends it back
|
|
199
|
+
const proof = computeClientProof(challenge, sharedSecret);
|
|
200
|
+
const verified = auth.verifyHmacResponse(challenge, proof, sharedSecret); // true
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### FIDO2 WebAuthn / Passkeys
|
|
204
|
+
|
|
205
|
+
Phishing-resistant browser authentication helpers — both registration and assertion flows.
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
import { auth } from 'mitigator';
|
|
209
|
+
|
|
210
|
+
// Generate base64url registration challenge
|
|
211
|
+
const challenge = auth.generatePasskeyChallenge();
|
|
212
|
+
|
|
213
|
+
// Verify client registration response against expected challenge and origin
|
|
214
|
+
const regResult = auth.verifyPasskeyRegistration(clientDataJSON, challenge, 'https://example.com');
|
|
215
|
+
|
|
216
|
+
// Parse binary authenticatorData buffer to extract credentialIds and keys
|
|
217
|
+
const credentials = auth.parseAuthenticatorData(authDataBuffer);
|
|
218
|
+
|
|
219
|
+
// Verify an authentication assertion (navigator.credentials.get flow)
|
|
220
|
+
// This implements WebAuthn Level 2 §7.2 including replay attack protection.
|
|
221
|
+
const assertResult = auth.verifyPasskeyAssertion(
|
|
222
|
+
clientDataJSON, // from browser response.clientDataJSON
|
|
223
|
+
storedChallenge, // challenge you sent to the browser
|
|
224
|
+
'https://example.com', // expected origin
|
|
225
|
+
storedSignCount, // signCount from DB (pass 0 on first use)
|
|
226
|
+
authDataBuffer, // from browser response.authenticatorData
|
|
227
|
+
signatureBuffer, // from browser response.signature
|
|
228
|
+
credentialPublicKeyPem, // public key stored during registration
|
|
229
|
+
);
|
|
230
|
+
if (!assertResult.verified) throw new Error(assertResult.error);
|
|
231
|
+
await db.updateSignCount(credentialId, assertResult.newSignCount!);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## 🏗️ Framework Integration
|
|
237
|
+
|
|
238
|
+
Mitigator comes with built-in presets for Express, Fastify, NestJS, and Next.js.
|
|
239
|
+
|
|
240
|
+
### Express
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
import express from 'express';
|
|
244
|
+
import { presets } from 'mitigator';
|
|
245
|
+
|
|
246
|
+
const app = express();
|
|
247
|
+
|
|
248
|
+
// Global security middleware (Headers, Rate Limiting, Secret Scanning)
|
|
249
|
+
app.use(presets.expressMiddleware({ rateLimit: true, rateLimitMax: 100 }));
|
|
250
|
+
|
|
251
|
+
// Secure Logger Chain (Tamper-proof logs via cryptographic linking)
|
|
252
|
+
const logger = presets.createSecureLogger(console);
|
|
253
|
+
logger.info('User logged in', { userId: 123 });
|
|
254
|
+
|
|
255
|
+
// Global Secure Error Handler
|
|
256
|
+
app.use(presets.expressErrorHandler);
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Fastify
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
import Fastify from 'fastify';
|
|
263
|
+
import { presets } from 'mitigator';
|
|
264
|
+
|
|
265
|
+
const fastify = Fastify();
|
|
266
|
+
|
|
267
|
+
// Register the security hook/plugin preset
|
|
268
|
+
fastify.register(presets.fastifyPlugin({ rateLimit: true, rateLimitMax: 100 }));
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### NestJS
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
|
|
275
|
+
import { presets } from 'mitigator';
|
|
276
|
+
|
|
277
|
+
@Module({})
|
|
278
|
+
export class AppModule implements NestModule {
|
|
279
|
+
configure(consumer: MiddlewareConsumer) {
|
|
280
|
+
// Configure rate limits
|
|
281
|
+
presets.NestJsMitigatorMiddleware.configure({ rateLimit: true, rateLimitMax: 100 });
|
|
282
|
+
|
|
283
|
+
// Apply globally
|
|
284
|
+
consumer.apply(presets.NestJsMitigatorMiddleware).forRoutes('*');
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Next.js Edge Middleware
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
// middleware.ts
|
|
293
|
+
import { NextResponse } from 'next/server';
|
|
294
|
+
import { presets } from 'mitigator';
|
|
295
|
+
|
|
296
|
+
export function middleware(request) {
|
|
297
|
+
const response = NextResponse.next();
|
|
298
|
+
return presets.nextJsMiddleware(request, response);
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## 🛡️ Automated Security Audit CLI
|
|
305
|
+
|
|
306
|
+
Mitigator features a recursive command-line security scanner (`mitigator-audit`) to check your configurations and files automatically in pre-commit hooks or CI/CD pipelines.
|
|
307
|
+
|
|
308
|
+
### Usage
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
# Scan the current directory
|
|
312
|
+
npx mitigator-audit
|
|
313
|
+
|
|
314
|
+
# Scan a specific directory
|
|
315
|
+
npx mitigator-audit ./src
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Checks Performed
|
|
319
|
+
|
|
320
|
+
- **Hardcoded Secret Detection**: Scans for high-entropy tokens and plain-text API credentials.
|
|
321
|
+
- **Potential Path Traversal**: Scans for raw user inputs mapped directly to file system operations.
|
|
322
|
+
- **Prototype Pollution Risks**: Scans for raw `JSON.parse` or `Object.assign` calls without Prototype Pollution filters.
|
|
323
|
+
- **Header Drift Detection**: Scans for express instances without security headers presets.
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## 🧪 Safety & Best Practices
|
|
328
|
+
|
|
329
|
+
### Prototype Lockdown
|
|
330
|
+
|
|
331
|
+
Prevent many prototype pollution attacks globally by freezing core prototypes. **Warning**: This may break some legacy libraries that modify built-ins.
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
import { utils } from 'mitigator';
|
|
335
|
+
|
|
336
|
+
utils.lockdownPrototypes(); // Freezes Object.prototype, Array.prototype, etc.
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Memory Wiping
|
|
340
|
+
|
|
341
|
+
For extremely sensitive data (like decrypted keys), overwrite the buffer once finished.
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
import { utils } from 'mitigator';
|
|
345
|
+
|
|
346
|
+
const keyBuffer = Buffer.from('high-entropy-secret');
|
|
347
|
+
// ... use key ...
|
|
348
|
+
utils.wipeBuffer(keyBuffer); // Fills buffer with zeros
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## 📜 License
|
|
354
|
+
|
|
355
|
+
ISC License - see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/bin/mitigator-audit.ts
|
|
32
|
+
var mitigator_audit_exports = {};
|
|
33
|
+
__export(mitigator_audit_exports, {
|
|
34
|
+
main: () => main,
|
|
35
|
+
runAudit: () => runAudit
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(mitigator_audit_exports);
|
|
38
|
+
var import_node_fs = require("fs");
|
|
39
|
+
var import_node_path = require("path");
|
|
40
|
+
|
|
41
|
+
// src/validate/index.ts
|
|
42
|
+
var import_node_crypto = require("crypto");
|
|
43
|
+
var https = __toESM(require("https"), 1);
|
|
44
|
+
var SECRET_PATTERNS = [
|
|
45
|
+
/AKIA[0-9A-Z]{16}/,
|
|
46
|
+
/-----BEGIN (RSA|OPENSSH|EC|PGP) PRIVATE KEY-----/,
|
|
47
|
+
/ghp_[a-zA-Z0-9]{36}/,
|
|
48
|
+
/sk_live_[a-zA-Z0-9]{24}/
|
|
49
|
+
];
|
|
50
|
+
var scanForSecrets = (input) => {
|
|
51
|
+
if (typeof input === "string") {
|
|
52
|
+
return SECRET_PATTERNS.some((pattern) => pattern.test(input));
|
|
53
|
+
}
|
|
54
|
+
if (typeof input === "object" && input !== null) {
|
|
55
|
+
return Object.values(input).some(scanForSecrets);
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// src/bin/mitigator-audit.ts
|
|
61
|
+
var findFiles = (dir, fileList = []) => {
|
|
62
|
+
try {
|
|
63
|
+
const files = (0, import_node_fs.readdirSync)(dir);
|
|
64
|
+
for (const file of files) {
|
|
65
|
+
if (file === "node_modules" || file === ".git" || file === "dist" || file === "coverage")
|
|
66
|
+
continue;
|
|
67
|
+
const filePath = (0, import_node_path.join)(dir, file);
|
|
68
|
+
const stat = (0, import_node_fs.statSync)(filePath);
|
|
69
|
+
if (stat.isDirectory()) {
|
|
70
|
+
findFiles(filePath, fileList);
|
|
71
|
+
} else {
|
|
72
|
+
const ext = (0, import_node_path.extname)(file);
|
|
73
|
+
if ([".js", ".ts", ".json", ".env", ".yml", ".yaml"].includes(ext)) {
|
|
74
|
+
fileList.push(filePath);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
} catch {
|
|
79
|
+
}
|
|
80
|
+
return fileList;
|
|
81
|
+
};
|
|
82
|
+
var auditFile = (filePath) => {
|
|
83
|
+
const result = { filePath, vulnerabilities: [] };
|
|
84
|
+
try {
|
|
85
|
+
const content = (0, import_node_fs.readFileSync)(filePath, "utf8");
|
|
86
|
+
const ext = (0, import_node_path.extname)(filePath);
|
|
87
|
+
if (ext !== ".json") {
|
|
88
|
+
const lines = content.split(/\r?\n/);
|
|
89
|
+
lines.forEach((line, idx) => {
|
|
90
|
+
if (scanForSecrets(line)) {
|
|
91
|
+
result.vulnerabilities.push({
|
|
92
|
+
type: "Hardcoded Secret",
|
|
93
|
+
severity: "HIGH",
|
|
94
|
+
message: `Potential plaintext API key or credential leak detected.`,
|
|
95
|
+
line: idx + 1
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (ext === ".js" || ext === ".ts") {
|
|
101
|
+
const traversalRegex = /fs\.(readFileSync|writeFileSync|readFile|writeFile)\(.*req\.(query|body|params)\./;
|
|
102
|
+
if (traversalRegex.test(content)) {
|
|
103
|
+
result.vulnerabilities.push({
|
|
104
|
+
type: "Potential Path Traversal",
|
|
105
|
+
severity: "HIGH",
|
|
106
|
+
message: "Direct user input passed to a file system operation without path lock validation."
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
if (content.includes("Object.assign(") || content.includes("JSON.parse(")) {
|
|
110
|
+
if (!content.includes("safeMerge") && !content.includes("safeJson") && !content.includes("lockdownPrototypes")) {
|
|
111
|
+
result.vulnerabilities.push({
|
|
112
|
+
type: "Prototype Pollution Risk",
|
|
113
|
+
severity: "MEDIUM",
|
|
114
|
+
message: "Raw JSON parsing or object assignment used without Prototype Pollution defense."
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (content.includes("express()") && !content.includes("presets.expressMiddleware") && !content.includes("helmet")) {
|
|
119
|
+
result.vulnerabilities.push({
|
|
120
|
+
type: "Missing Security Headers",
|
|
121
|
+
severity: "MEDIUM",
|
|
122
|
+
message: "Express application instance created but no security middleware preset detected."
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
return result;
|
|
129
|
+
};
|
|
130
|
+
var runAudit = (targetDir = ".") => {
|
|
131
|
+
const files = findFiles(targetDir);
|
|
132
|
+
const results = [];
|
|
133
|
+
for (const file of files) {
|
|
134
|
+
const res = auditFile(file);
|
|
135
|
+
if (res.vulnerabilities.length > 0) {
|
|
136
|
+
results.push(res);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return results;
|
|
140
|
+
};
|
|
141
|
+
var main = () => {
|
|
142
|
+
const args = process.argv.slice(2);
|
|
143
|
+
const target = args[0] || ".";
|
|
144
|
+
console.log(
|
|
145
|
+
`\u{1F6E1}\uFE0F Mitigator Security Audit: Scanning [${target}] for vulnerabilities and configuration drifts...
|
|
146
|
+
`
|
|
147
|
+
);
|
|
148
|
+
const results = runAudit(target);
|
|
149
|
+
let totalHigh = 0;
|
|
150
|
+
let totalMedium = 0;
|
|
151
|
+
if (results.length === 0) {
|
|
152
|
+
console.log("\u2705 No security vulnerabilities or drifts found. Keep up the high standard!");
|
|
153
|
+
process.exit(0);
|
|
154
|
+
}
|
|
155
|
+
results.forEach((res) => {
|
|
156
|
+
console.log(`\u{1F4C2} File: ${res.filePath}`);
|
|
157
|
+
res.vulnerabilities.forEach((vuln) => {
|
|
158
|
+
const color = vuln.severity === "HIGH" ? "\x1B[31m[HIGH]\x1B[0m" : "\x1B[33m[MEDIUM]\x1B[0m";
|
|
159
|
+
if (vuln.severity === "HIGH") totalHigh++;
|
|
160
|
+
if (vuln.severity === "MEDIUM") totalMedium++;
|
|
161
|
+
const lineStr = vuln.line ? ` (line ${vuln.line})` : "";
|
|
162
|
+
console.log(` ${color} ${vuln.type}: ${vuln.message}${lineStr}`);
|
|
163
|
+
});
|
|
164
|
+
console.log("");
|
|
165
|
+
});
|
|
166
|
+
console.log(
|
|
167
|
+
`\u{1F4CA} Audit Summary: Found ${totalHigh} HIGH and ${totalMedium} MEDIUM severity alerts.`
|
|
168
|
+
);
|
|
169
|
+
if (totalHigh > 0) {
|
|
170
|
+
console.log(
|
|
171
|
+
"\x1B[31m\u274C Audit Failed: Critical vulnerabilities must be resolved before merging.\x1B[0m"
|
|
172
|
+
);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
} else {
|
|
175
|
+
console.log("\x1B[32m\u26A0\uFE0F Audit Passed with warnings.\x1B[0m");
|
|
176
|
+
process.exit(0);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
if (typeof require !== "undefined" && require.main === module || process.argv[1] && (process.argv[1].endsWith("mitigator-audit") || process.argv[1].endsWith("mitigator-audit.js") || process.argv[1].endsWith("mitigator-audit.ts"))) {
|
|
180
|
+
main();
|
|
181
|
+
}
|
|
182
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
183
|
+
0 && (module.exports = {
|
|
184
|
+
main,
|
|
185
|
+
runAudit
|
|
186
|
+
});
|
|
187
|
+
//# sourceMappingURL=mitigator-audit.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/bin/mitigator-audit.ts","../../src/validate/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { readFileSync, readdirSync, statSync } from 'node:fs';\nimport { join, extname } from 'node:path';\nimport { scanForSecrets } from '../validate/index.js';\n\ninterface AuditResult {\n filePath: string;\n vulnerabilities: {\n type: string;\n severity: 'HIGH' | 'MEDIUM' | 'LOW';\n message: string;\n line?: number;\n }[];\n}\n\nconst findFiles = (dir: string, fileList: string[] = []): string[] => {\n try {\n const files = readdirSync(dir);\n for (const file of files) {\n if (file === 'node_modules' || file === '.git' || file === 'dist' || file === 'coverage')\n continue;\n const filePath = join(dir, file);\n const stat = statSync(filePath);\n if (stat.isDirectory()) {\n findFiles(filePath, fileList);\n } else {\n const ext = extname(file);\n if (['.js', '.ts', '.json', '.env', '.yml', '.yaml'].includes(ext)) {\n fileList.push(filePath);\n }\n }\n }\n } catch {}\n return fileList;\n};\n\nconst auditFile = (filePath: string): AuditResult => {\n const result: AuditResult = { filePath, vulnerabilities: [] };\n try {\n const content = readFileSync(filePath, 'utf8');\n const ext = extname(filePath);\n\n // 1. Plaintext Secret Scanning\n if (ext !== '.json') {\n const lines = content.split(/\\r?\\n/);\n lines.forEach((line, idx) => {\n if (scanForSecrets(line)) {\n result.vulnerabilities.push({\n type: 'Hardcoded Secret',\n severity: 'HIGH',\n message: `Potential plaintext API key or credential leak detected.`,\n line: idx + 1,\n });\n }\n });\n }\n\n // 2. Dangerous File Sync / Path Traversal\n if (ext === '.js' || ext === '.ts') {\n const traversalRegex =\n /fs\\.(readFileSync|writeFileSync|readFile|writeFile)\\(.*req\\.(query|body|params)\\./;\n if (traversalRegex.test(content)) {\n result.vulnerabilities.push({\n type: 'Potential Path Traversal',\n severity: 'HIGH',\n message:\n 'Direct user input passed to a file system operation without path lock validation.',\n });\n }\n\n // 3. Unsafe Merging without prototype check\n if (content.includes('Object.assign(') || content.includes('JSON.parse(')) {\n if (\n !content.includes('safeMerge') &&\n !content.includes('safeJson') &&\n !content.includes('lockdownPrototypes')\n ) {\n result.vulnerabilities.push({\n type: 'Prototype Pollution Risk',\n severity: 'MEDIUM',\n message:\n 'Raw JSON parsing or object assignment used without Prototype Pollution defense.',\n });\n }\n }\n\n // 4. Missing secure headers in standard http/express setups\n if (\n content.includes('express()') &&\n !content.includes('presets.expressMiddleware') &&\n !content.includes('helmet')\n ) {\n result.vulnerabilities.push({\n type: 'Missing Security Headers',\n severity: 'MEDIUM',\n message:\n 'Express application instance created but no security middleware preset detected.',\n });\n }\n }\n } catch {}\n return result;\n};\n\nexport const runAudit = (targetDir: string = '.'): AuditResult[] => {\n const files = findFiles(targetDir);\n const results: AuditResult[] = [];\n for (const file of files) {\n const res = auditFile(file);\n if (res.vulnerabilities.length > 0) {\n results.push(res);\n }\n }\n return results;\n};\n\n// Main Execution\nexport const main = () => {\n const args = process.argv.slice(2);\n const target = args[0] || '.';\n console.log(\n `🛡️ Mitigator Security Audit: Scanning [${target}] for vulnerabilities and configuration drifts...\\n`,\n );\n\n const results = runAudit(target);\n let totalHigh = 0;\n let totalMedium = 0;\n\n if (results.length === 0) {\n console.log('✅ No security vulnerabilities or drifts found. Keep up the high standard!');\n process.exit(0);\n }\n\n results.forEach((res) => {\n console.log(`📂 File: ${res.filePath}`);\n res.vulnerabilities.forEach((vuln) => {\n const color = vuln.severity === 'HIGH' ? '\\x1b[31m[HIGH]\\x1b[0m' : '\\x1b[33m[MEDIUM]\\x1b[0m';\n if (vuln.severity === 'HIGH') totalHigh++;\n if (vuln.severity === 'MEDIUM') totalMedium++;\n const lineStr = vuln.line ? ` (line ${vuln.line})` : '';\n console.log(` ${color} ${vuln.type}: ${vuln.message}${lineStr}`);\n });\n console.log('');\n });\n\n console.log(\n `📊 Audit Summary: Found ${totalHigh} HIGH and ${totalMedium} MEDIUM severity alerts.`,\n );\n if (totalHigh > 0) {\n console.log(\n '\\x1b[31m❌ Audit Failed: Critical vulnerabilities must be resolved before merging.\\x1b[0m',\n );\n process.exit(1);\n } else {\n console.log('\\x1b[32m⚠️ Audit Passed with warnings.\\x1b[0m');\n process.exit(0);\n }\n};\n\n// Only execute when run directly\n/* v8 ignore next 11 */\nif (\n (typeof require !== 'undefined' && require.main === module) ||\n (process.argv[1] &&\n (process.argv[1].endsWith('mitigator-audit') ||\n process.argv[1].endsWith('mitigator-audit.js') ||\n process.argv[1].endsWith('mitigator-audit.ts')))\n) {\n main();\n}\n","import { createHash } from 'node:crypto';\nimport * as https from 'node:https';\n\n/**\n * Result returned by `checkPwnedPassword`.\n * Always resolves (never rejects) to preserve fail-open availability semantics.\n */\nexport interface CheckPwnedResult {\n /** Number of times this password appeared in known data breaches. 0 if not found. */\n count: number;\n /**\n * Whether the HIBP API was reachable during this check.\n * If `false`, the result is inconclusive — the password may or may not be compromised.\n * Callers should treat `apiAvailable: false` as a signal to retry or log a warning.\n */\n apiAvailable: boolean;\n}\n\n/**\n * Checks if a password has been leaked in a data breach using the Have I Been Pwned (HIBP) API.\n * Uses k-Anonymity (sending only the first 5 characters of the SHA-1 hash) to ensure\n * the password is never exposed to the API.\n *\n * Always resolves — never rejects. If the API is unreachable, `apiAvailable` will be `false`\n * and `count` will be `0` (inconclusive). Callers should check `apiAvailable` before\n * treating a zero count as \"password is clean\".\n *\n * @param password The password to check.\n * @returns {Promise<CheckPwnedResult>} Structured result with breach count and API availability.\n *\n * @example\n * const { count, apiAvailable } = await checkPwnedPassword('hunter2');\n * if (!apiAvailable) logger.warn('HIBP API unreachable — skipping pwned check');\n * else if (count > 0) throw new Error('Password found in data breaches');\n */\nexport const checkPwnedPassword = (password: string): Promise<CheckPwnedResult> => {\n return new Promise((resolve) => {\n const hash = createHash('sha1').update(password).digest('hex').toUpperCase();\n const prefix = hash.slice(0, 5);\n const suffix = hash.slice(5);\n\n https\n .get(`https://api.pwnedpasswords.com/range/${prefix}`, (res) => {\n let data = '';\n res.on('data', (chunk) => (data += chunk));\n res.on('end', () => {\n const lines = data.split('\\n');\n for (const line of lines) {\n const [hashSuffix, count] = line.split(':');\n if (hashSuffix === suffix) {\n return resolve({ count: Number.parseInt(count.trim()), apiAvailable: true });\n }\n }\n resolve({ count: 0, apiAvailable: true });\n });\n })\n .on('error', (err) => {\n // Fail-open: don't block authentication when HIBP is unreachable.\n // apiAvailable: false lets the caller decide how to handle the degraded state.\n console.error('Mitigator: HIBP API connection error.', err);\n resolve({ count: 0, apiAvailable: false });\n });\n });\n};\n\n/**\n * Patterns for secrets.\n */\nexport const SECRET_PATTERNS = [\n /AKIA[0-9A-Z]{16}/,\n /-----BEGIN (RSA|OPENSSH|EC|PGP) PRIVATE KEY-----/,\n /ghp_[a-zA-Z0-9]{36}/,\n /sk_live_[a-zA-Z0-9]{24}/,\n];\n\n/**\n * Scans for secrets.\n */\nexport const scanForSecrets = (input: any): boolean => {\n if (typeof input === 'string') {\n return SECRET_PATTERNS.some((pattern) => pattern.test(input));\n }\n if (typeof input === 'object' && input !== null) {\n return Object.values(input).some(scanForSecrets);\n }\n return false;\n};\n\n/**\n * Weak password check.\n */\nexport const isWeakPassword = (password: string): boolean => {\n if (password.length < 8) return true;\n const hasLower = /[a-z]/.test(password);\n const hasUpper = /[A-Z]/.test(password);\n const hasNumber = /\\d/.test(password);\n const hasSpecial = /[^a-zA-Z0-9]/.test(password);\n const types = [hasLower, hasUpper, hasNumber, hasSpecial].filter(Boolean).length;\n if (types < 2) return true;\n const common = ['password', '123456', 'qwerty', 'admin123', 'password123', '12345678'];\n if (common.includes(password.toLowerCase())) return true;\n return false;\n};\n\n/**\n * Schema types.\n */\nexport type Schema = {\n [key: string]: 'string' | 'number' | 'boolean' | 'object' | 'array';\n};\n\n/**\n * Type validation.\n */\nexport const isType = (val: any, type: Schema[keyof Schema]): boolean => {\n if (type === 'array') return Array.isArray(val);\n return typeof val === type && val !== null;\n};\n\n/**\n * Schema enforcement.\n */\nexport const enforceSchema = <T extends Record<string, any>>(\n data: any,\n schema: Schema,\n): T | null => {\n if (typeof data !== 'object' || data === null || Array.isArray(data)) return null;\n const result: any = {};\n for (const key of Object.keys(schema)) {\n const expectedType = schema[key];\n const value = data[key];\n if (value === undefined || !isType(value, expectedType)) return null;\n result[key] = value;\n }\n return result;\n};\n\n/**\n * Email validation.\n */\nexport const isEmail = (input: string): boolean => {\n return /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(\n input,\n );\n};\n\n/**\n * Injection pattern detection (Heuristic).\n * Detects common SQL, NoSQL, and Command Injection payloads.\n */\nexport const hasInjectionPattern = (input: string): boolean => {\n if (typeof input !== 'string') return false;\n\n const dangerousPatterns = [\n // SQL Injection\n /(\\b(SELECT|INSERT|UPDATE|DELETE|DROP|ALTER|CREATE|EXEC|UNION|ALL|ANY|SOME)\\b.*\\b(FROM|INTO|SET|TABLE|DATABASE)\\b)/i,\n /'\\s*OR\\s+'?1'?\\s*=\\s*'?1/i,\n /\"\\s*OR\\s+\"?1\"?\\s*=\\s*\"?1/i,\n /--\\s*$/,\n /;\\s*(WAITFOR|DELAY|SLEEP)/i,\n /;\\s*(EXEC|EXECUTE)\\b/i,\n // NoSQL Injection\n /\\$(where|gt|lt|gte|lte|ne|in|nin|regex|expr|eq)/i,\n /\\{\\s*\\$ne\\s*:/i,\n // Command Injection\n /(;|\\||&&|\\|\\||`|\\$)\\s*(cat|ls|pwd|whoami|id|echo|bash|sh|ping|curl|wget)/i,\n ];\n return dangerousPatterns.some((pattern) => pattern.test(input));\n};\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
interface AuditResult {
|
|
3
|
+
filePath: string;
|
|
4
|
+
vulnerabilities: {
|
|
5
|
+
type: string;
|
|
6
|
+
severity: 'HIGH' | 'MEDIUM' | 'LOW';
|
|
7
|
+
message: string;
|
|
8
|
+
line?: number;
|
|
9
|
+
}[];
|
|
10
|
+
}
|
|
11
|
+
declare const runAudit: (targetDir?: string) => AuditResult[];
|
|
12
|
+
declare const main: () => never;
|
|
13
|
+
|
|
14
|
+
export { main, runAudit };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
interface AuditResult {
|
|
3
|
+
filePath: string;
|
|
4
|
+
vulnerabilities: {
|
|
5
|
+
type: string;
|
|
6
|
+
severity: 'HIGH' | 'MEDIUM' | 'LOW';
|
|
7
|
+
message: string;
|
|
8
|
+
line?: number;
|
|
9
|
+
}[];
|
|
10
|
+
}
|
|
11
|
+
declare const runAudit: (targetDir?: string) => AuditResult[];
|
|
12
|
+
declare const main: () => never;
|
|
13
|
+
|
|
14
|
+
export { main, runAudit };
|