contextguard 0.1.6 → 0.1.8
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 +18 -18
- package/SECURITY.md +1 -1
- package/dist/mcp-security-wrapper.js +41 -14
- package/examples/config/config.json +10 -3
- package/package.json +3 -2
- package/src/mcp-security-wrapper.ts +56 -20
package/README.md
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/contextguard)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
[](https://www.npmjs.com/package/contextguard)
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
<!-- [](https://github.com/amironi/contextguard/actions) -->
|
|
9
10
|
|
|
10
11
|
⭐ **Star us on GitHub if you find this useful!** ⭐
|
|
11
12
|
|
|
@@ -33,19 +34,19 @@
|
|
|
33
34
|
|
|
34
35
|
## 🚀 Quick Start
|
|
35
36
|
|
|
36
|
-
### Installation
|
|
37
|
+
### Installation
|
|
37
38
|
|
|
38
39
|
```bash
|
|
39
40
|
npm install -g contextguard
|
|
40
41
|
```
|
|
41
42
|
|
|
42
|
-
### Basic Usage
|
|
43
|
+
### Basic Usage (CLI - optional)
|
|
43
44
|
|
|
44
45
|
```bash
|
|
45
46
|
contextguard --server "node your-mcp-server.js"
|
|
46
47
|
```
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
### Basic Usage (Claude Desktop)
|
|
49
50
|
|
|
50
51
|
Update your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
51
52
|
|
|
@@ -53,8 +54,13 @@ Update your Claude Desktop config (`~/Library/Application Support/Claude/claude_
|
|
|
53
54
|
{
|
|
54
55
|
"mcpServers": {
|
|
55
56
|
"secured-server": {
|
|
56
|
-
"command": "
|
|
57
|
-
"args": [
|
|
57
|
+
"command": "contextguard",
|
|
58
|
+
"args": [
|
|
59
|
+
"--server",
|
|
60
|
+
"node /path/to/your-server.js",
|
|
61
|
+
"--config",
|
|
62
|
+
"/path/to/config.json"
|
|
63
|
+
]
|
|
58
64
|
}
|
|
59
65
|
}
|
|
60
66
|
}
|
|
@@ -62,7 +68,7 @@ Update your Claude Desktop config (`~/Library/Application Support/Claude/claude_
|
|
|
62
68
|
|
|
63
69
|
**That's it!** Your MCP server is now protected. 🛡️
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
#### [See Example below: Testing ContextGuard](#-example-testing-contextguard)
|
|
66
72
|
|
|
67
73
|
## ✨ Features
|
|
68
74
|
|
|
@@ -126,7 +132,7 @@ Create `config.json` for advanced settings:
|
|
|
126
132
|
"enablePathTraversalPrevention": true,
|
|
127
133
|
"allowedFilePaths": ["/home/user/safe-directory"],
|
|
128
134
|
"logLevel": "info",
|
|
129
|
-
"logPath": "/
|
|
135
|
+
"logPath": "/tmp/mcp_security.log"
|
|
130
136
|
}
|
|
131
137
|
```
|
|
132
138
|
|
|
@@ -161,7 +167,9 @@ All security events are logged in JSON format:
|
|
|
161
167
|
}
|
|
162
168
|
```
|
|
163
169
|
|
|
164
|
-
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 🧪 Example: Testing ContextGuard
|
|
165
173
|
|
|
166
174
|
Want to see the protection in action? Try these tests:
|
|
167
175
|
|
|
@@ -198,6 +206,7 @@ Create `config.json`:
|
|
|
198
206
|
"enablePromptInjectionDetection": true,
|
|
199
207
|
"enableSensitiveDataDetection": true,
|
|
200
208
|
"enablePathTraversalPrevention": true,
|
|
209
|
+
"logPath": "/tmp/mcp_security.log",
|
|
201
210
|
"allowedFilePaths": ["/tmp/safe-directory"],
|
|
202
211
|
"logLevel": "debug"
|
|
203
212
|
}
|
|
@@ -285,15 +294,6 @@ We welcome contributions! Here's how to get started:
|
|
|
285
294
|
6. **Push:** `git push origin feature/amazing-feature`
|
|
286
295
|
7. **Open a Pull Request**
|
|
287
296
|
|
|
288
|
-
### Development Setup
|
|
289
|
-
|
|
290
|
-
```bash
|
|
291
|
-
git clone https://github.com/amironi/contextguard.git
|
|
292
|
-
cd contextguard
|
|
293
|
-
npm install
|
|
294
|
-
npm run dev
|
|
295
|
-
```
|
|
296
|
-
|
|
297
297
|
---
|
|
298
298
|
|
|
299
299
|
## 📄 License & Support
|
package/SECURITY.md
CHANGED
|
@@ -193,7 +193,7 @@ We plan to conduct regular security audits as the project matures.
|
|
|
193
193
|
"confidential"
|
|
194
194
|
],
|
|
195
195
|
"logLevel": "info",
|
|
196
|
-
"logFile": "/
|
|
196
|
+
"logFile": "/tmp/mcp_security.log",
|
|
197
197
|
"alertWebhook": "https://your-monitoring-service.com/webhook"
|
|
198
198
|
}
|
|
199
199
|
```
|
|
@@ -60,7 +60,7 @@ class SecurityPolicy {
|
|
|
60
60
|
/(?:password|secret|api[_-]?key|token)\s*[:=]\s*['"]?[\w\-.]+['"]?/gi,
|
|
61
61
|
/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g, // Email
|
|
62
62
|
/\b\d{3}-\d{2}-\d{4}\b/g, // SSN
|
|
63
|
-
/sk-[a-zA-Z0-9]{
|
|
63
|
+
/sk-[a-zA-Z0-9]{20,}/g, // OpenAI API keys (20+ chars)
|
|
64
64
|
/ghp_[a-zA-Z0-9]{36}/g, // GitHub tokens
|
|
65
65
|
/AKIA[0-9A-Z]{16}/g, // AWS Access Keys
|
|
66
66
|
];
|
|
@@ -319,20 +319,48 @@ class MCPSecurityWrapper {
|
|
|
319
319
|
}
|
|
320
320
|
}
|
|
321
321
|
handleServerOutput(output) {
|
|
322
|
-
//
|
|
323
|
-
process.stdout.write(output);
|
|
324
|
-
// Buffer and parse for logging
|
|
322
|
+
// Buffer and parse for security scanning
|
|
325
323
|
this.serverMessageBuffer += output;
|
|
326
324
|
const lines = this.serverMessageBuffer.split("\n");
|
|
327
325
|
this.serverMessageBuffer = lines.pop() || "";
|
|
328
326
|
for (const line of lines) {
|
|
329
327
|
if (line.trim()) {
|
|
328
|
+
let shouldForward = true;
|
|
330
329
|
try {
|
|
331
330
|
const message = JSON.parse(line);
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
331
|
+
// Check for sensitive data in response
|
|
332
|
+
const violations = [];
|
|
333
|
+
const responseStr = JSON.stringify(message.result || message);
|
|
334
|
+
const sensitiveViolations = this.policy.checkSensitiveData(responseStr);
|
|
335
|
+
violations.push(...sensitiveViolations);
|
|
336
|
+
if (violations.length > 0) {
|
|
337
|
+
this.logger.logEvent("SENSITIVE_DATA_LEAK", "CRITICAL", {
|
|
338
|
+
violations,
|
|
339
|
+
responseId: message.id,
|
|
340
|
+
}, this.sessionId);
|
|
341
|
+
console.error(`\n🚨 SENSITIVE DATA DETECTED IN RESPONSE:\n${violations.join("\n")}\n`);
|
|
342
|
+
console.error("🚫 RESPONSE BLOCKED\n");
|
|
343
|
+
// Send sanitized error response instead
|
|
344
|
+
if (message.id !== undefined) {
|
|
345
|
+
const errorResponse = {
|
|
346
|
+
jsonrpc: message.jsonrpc,
|
|
347
|
+
id: message.id,
|
|
348
|
+
error: {
|
|
349
|
+
code: -32001,
|
|
350
|
+
message: "Security violation: Response contains sensitive data",
|
|
351
|
+
data: { violations },
|
|
352
|
+
},
|
|
353
|
+
};
|
|
354
|
+
process.stdout.write(JSON.stringify(errorResponse) + "\n");
|
|
355
|
+
}
|
|
356
|
+
shouldForward = false;
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
this.logger.logEvent("SERVER_RESPONSE", "LOW", {
|
|
360
|
+
id: message.id,
|
|
361
|
+
hasError: !!message.error,
|
|
362
|
+
}, this.sessionId);
|
|
363
|
+
}
|
|
336
364
|
}
|
|
337
365
|
catch (err) {
|
|
338
366
|
// Log parse errors for server output
|
|
@@ -341,6 +369,10 @@ class MCPSecurityWrapper {
|
|
|
341
369
|
line: line.substring(0, 100),
|
|
342
370
|
}, this.sessionId);
|
|
343
371
|
}
|
|
372
|
+
// Forward the line if not blocked
|
|
373
|
+
if (shouldForward) {
|
|
374
|
+
process.stdout.write(line + "\n");
|
|
375
|
+
}
|
|
344
376
|
}
|
|
345
377
|
}
|
|
346
378
|
}
|
|
@@ -353,18 +385,13 @@ async function main() {
|
|
|
353
385
|
MCP Security Wrapper - MVP
|
|
354
386
|
|
|
355
387
|
Usage:
|
|
356
|
-
|
|
388
|
+
contextguard --server "node server.js" --config config.json
|
|
357
389
|
|
|
358
390
|
Options:
|
|
359
391
|
--server <command> Command to start the MCP server (required)
|
|
360
392
|
--config <file> Path to security config JSON file (optional)
|
|
361
393
|
--help Show this help message
|
|
362
394
|
|
|
363
|
-
Config file options:
|
|
364
|
-
logPath: Custom path for security log file (default: ./mcp_security.log)
|
|
365
|
-
|
|
366
|
-
Example:
|
|
367
|
-
npx ts-node mcp-security-wrapper.ts --server "node server.js" --config security.json
|
|
368
395
|
`);
|
|
369
396
|
process.exit(0);
|
|
370
397
|
}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"maxToolCallsPerMinute": 30,
|
|
3
|
-
"blockedPatterns": [
|
|
3
|
+
"blockedPatterns": [
|
|
4
|
+
"ignore previous instructions",
|
|
5
|
+
"system prompt",
|
|
6
|
+
"confidential"
|
|
7
|
+
],
|
|
4
8
|
"allowedFilePaths": [
|
|
5
|
-
"
|
|
6
|
-
"/
|
|
9
|
+
"/var/app/data",
|
|
10
|
+
"/home/user/safe-directory"
|
|
7
11
|
],
|
|
8
12
|
"alertThreshold": 5,
|
|
9
13
|
"enablePromptInjectionDetection": true,
|
|
10
14
|
"enableSensitiveDataDetection": true,
|
|
15
|
+
"enablePathTraversalPrevention": true,
|
|
16
|
+
"enableRateLimiting": true,
|
|
17
|
+
"logLevel": "debug",
|
|
11
18
|
"logPath": "/tmp/mcp_security.log"
|
|
12
19
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "contextguard",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Security monitoring wrapper for MCP servers",
|
|
5
5
|
"main": "dist/mcp-security-wrapper.js",
|
|
6
6
|
"types": "dist/mcp-security-wrapper.d.ts",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"start": "node dist/server.js",
|
|
16
16
|
"dev": "ts-node src/mcp-security-wrapper.ts",
|
|
17
17
|
"test": "jest",
|
|
18
|
-
"lint": "eslint ."
|
|
18
|
+
"lint": "eslint .",
|
|
19
|
+
"release": "npm publish & npm install -g contextguard"
|
|
19
20
|
},
|
|
20
21
|
"keywords": [
|
|
21
22
|
"mcp",
|
|
@@ -65,7 +65,7 @@ class SecurityPolicy {
|
|
|
65
65
|
/(?:password|secret|api[_-]?key|token)\s*[:=]\s*['"]?[\w\-.]+['"]?/gi,
|
|
66
66
|
/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g, // Email
|
|
67
67
|
/\b\d{3}-\d{2}-\d{4}\b/g, // SSN
|
|
68
|
-
/sk-[a-zA-Z0-9]{
|
|
68
|
+
/sk-[a-zA-Z0-9]{20,}/g, // OpenAI API keys (20+ chars)
|
|
69
69
|
/ghp_[a-zA-Z0-9]{36}/g, // GitHub tokens
|
|
70
70
|
/AKIA[0-9A-Z]{16}/g, // AWS Access Keys
|
|
71
71
|
];
|
|
@@ -427,27 +427,63 @@ class MCPSecurityWrapper {
|
|
|
427
427
|
}
|
|
428
428
|
|
|
429
429
|
private handleServerOutput(output: string): void {
|
|
430
|
-
//
|
|
431
|
-
process.stdout.write(output);
|
|
432
|
-
|
|
433
|
-
// Buffer and parse for logging
|
|
430
|
+
// Buffer and parse for security scanning
|
|
434
431
|
this.serverMessageBuffer += output;
|
|
435
432
|
const lines = this.serverMessageBuffer.split("\n");
|
|
436
433
|
this.serverMessageBuffer = lines.pop() || "";
|
|
437
434
|
|
|
438
435
|
for (const line of lines) {
|
|
439
436
|
if (line.trim()) {
|
|
437
|
+
let shouldForward = true;
|
|
440
438
|
try {
|
|
441
439
|
const message: MCPMessage = JSON.parse(line);
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
440
|
+
|
|
441
|
+
// Check for sensitive data in response
|
|
442
|
+
const violations: string[] = [];
|
|
443
|
+
const responseStr = JSON.stringify(message.result || message);
|
|
444
|
+
const sensitiveViolations = this.policy.checkSensitiveData(responseStr);
|
|
445
|
+
violations.push(...sensitiveViolations);
|
|
446
|
+
|
|
447
|
+
if (violations.length > 0) {
|
|
448
|
+
this.logger.logEvent(
|
|
449
|
+
"SENSITIVE_DATA_LEAK",
|
|
450
|
+
"CRITICAL",
|
|
451
|
+
{
|
|
452
|
+
violations,
|
|
453
|
+
responseId: message.id,
|
|
454
|
+
},
|
|
455
|
+
this.sessionId
|
|
456
|
+
);
|
|
457
|
+
console.error(
|
|
458
|
+
`\n🚨 SENSITIVE DATA DETECTED IN RESPONSE:\n${violations.join("\n")}\n`
|
|
459
|
+
);
|
|
460
|
+
console.error("🚫 RESPONSE BLOCKED\n");
|
|
461
|
+
|
|
462
|
+
// Send sanitized error response instead
|
|
463
|
+
if (message.id !== undefined) {
|
|
464
|
+
const errorResponse: MCPMessage = {
|
|
465
|
+
jsonrpc: message.jsonrpc,
|
|
466
|
+
id: message.id,
|
|
467
|
+
error: {
|
|
468
|
+
code: -32001,
|
|
469
|
+
message: "Security violation: Response contains sensitive data",
|
|
470
|
+
data: { violations },
|
|
471
|
+
},
|
|
472
|
+
};
|
|
473
|
+
process.stdout.write(JSON.stringify(errorResponse) + "\n");
|
|
474
|
+
}
|
|
475
|
+
shouldForward = false;
|
|
476
|
+
} else {
|
|
477
|
+
this.logger.logEvent(
|
|
478
|
+
"SERVER_RESPONSE",
|
|
479
|
+
"LOW",
|
|
480
|
+
{
|
|
481
|
+
id: message.id,
|
|
482
|
+
hasError: !!message.error,
|
|
483
|
+
},
|
|
484
|
+
this.sessionId
|
|
485
|
+
);
|
|
486
|
+
}
|
|
451
487
|
} catch (err) {
|
|
452
488
|
// Log parse errors for server output
|
|
453
489
|
this.logger.logEvent(
|
|
@@ -460,6 +496,11 @@ class MCPSecurityWrapper {
|
|
|
460
496
|
this.sessionId
|
|
461
497
|
);
|
|
462
498
|
}
|
|
499
|
+
|
|
500
|
+
// Forward the line if not blocked
|
|
501
|
+
if (shouldForward) {
|
|
502
|
+
process.stdout.write(line + "\n");
|
|
503
|
+
}
|
|
463
504
|
}
|
|
464
505
|
}
|
|
465
506
|
}
|
|
@@ -472,18 +513,13 @@ async function main() {
|
|
|
472
513
|
MCP Security Wrapper - MVP
|
|
473
514
|
|
|
474
515
|
Usage:
|
|
475
|
-
|
|
516
|
+
contextguard --server "node server.js" --config config.json
|
|
476
517
|
|
|
477
518
|
Options:
|
|
478
519
|
--server <command> Command to start the MCP server (required)
|
|
479
520
|
--config <file> Path to security config JSON file (optional)
|
|
480
521
|
--help Show this help message
|
|
481
522
|
|
|
482
|
-
Config file options:
|
|
483
|
-
logPath: Custom path for security log file (default: ./mcp_security.log)
|
|
484
|
-
|
|
485
|
-
Example:
|
|
486
|
-
npx ts-node mcp-security-wrapper.ts --server "node server.js" --config security.json
|
|
487
523
|
`);
|
|
488
524
|
process.exit(0);
|
|
489
525
|
}
|