@solongate/proxy 0.2.3 → 0.2.5
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/dist/index.js +21 -15
- package/dist/init.js +21 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -472,20 +472,27 @@ const DANGEROUS_COMMANDS = [
|
|
|
472
472
|
/\\bgit\\s+reset\\s+--hard\\b/i,
|
|
473
473
|
];
|
|
474
474
|
|
|
475
|
-
function
|
|
475
|
+
function checkPath(val) {
|
|
476
476
|
if (typeof val !== 'string' || val.length < 2) return null;
|
|
477
477
|
for (const p of PATH_TRAVERSAL) if (p.test(val)) return 'Path traversal detected';
|
|
478
478
|
for (const p of SENSITIVE_PATHS) if (p.test(val)) return 'Sensitive file access blocked';
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function checkValue(val) {
|
|
483
|
+
if (typeof val !== 'string' || val.length < 2) return null;
|
|
479
484
|
for (const p of SSRF) if (p.test(val)) return 'SSRF attempt blocked';
|
|
480
485
|
for (const p of SQL_INJECTION) if (p.test(val)) return 'SQL injection detected';
|
|
481
486
|
if (val.length > 10000) return 'Input too long (max 10000 chars)';
|
|
482
487
|
return null;
|
|
483
488
|
}
|
|
484
489
|
|
|
490
|
+
// Arguments that contain file paths
|
|
491
|
+
const PATH_ARGS = ['file_path', 'path', 'pattern', 'directory', 'url', 'uri', 'notebook_path'];
|
|
492
|
+
|
|
485
493
|
function checkBashCommand(cmd) {
|
|
486
494
|
if (typeof cmd !== 'string') return null;
|
|
487
495
|
for (const p of DANGEROUS_COMMANDS) if (p.test(cmd)) return 'Dangerous command blocked: ' + cmd.slice(0, 80);
|
|
488
|
-
for (const p of SHELL_INJECTION) if (p.test(cmd)) return null; // shell injection is normal for Bash
|
|
489
496
|
return null;
|
|
490
497
|
}
|
|
491
498
|
|
|
@@ -505,20 +512,17 @@ process.stdin.on('end', async () => {
|
|
|
505
512
|
threat = checkBashCommand(args.command);
|
|
506
513
|
}
|
|
507
514
|
|
|
508
|
-
// Check
|
|
515
|
+
// Check arguments based on type
|
|
509
516
|
if (!threat) {
|
|
510
517
|
for (const [key, val] of Object.entries(args)) {
|
|
511
|
-
if (tool === 'Bash' && key === 'command') continue;
|
|
512
|
-
|
|
513
|
-
if (
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
threat = checkValue(v);
|
|
518
|
-
if (threat) { threat = threat + ' (in ' + key + ')'; break; }
|
|
519
|
-
}
|
|
520
|
-
if (threat) break;
|
|
518
|
+
if (tool === 'Bash' && key === 'command') continue;
|
|
519
|
+
if (key === 'content' || key === 'new_source' || key === 'new_string' || key === 'old_string' || key === 'description') continue;
|
|
520
|
+
if (PATH_ARGS.includes(key)) {
|
|
521
|
+
threat = checkPath(val);
|
|
522
|
+
} else {
|
|
523
|
+
threat = checkValue(val);
|
|
521
524
|
}
|
|
525
|
+
if (threat) { threat = threat + ' (in ' + key + ')'; break; }
|
|
522
526
|
}
|
|
523
527
|
}
|
|
524
528
|
|
|
@@ -539,8 +543,10 @@ process.stdin.on('end', async () => {
|
|
|
539
543
|
signal: AbortSignal.timeout(5000),
|
|
540
544
|
}).catch(() => {});
|
|
541
545
|
}
|
|
542
|
-
// Exit 2 = BLOCK.
|
|
543
|
-
|
|
546
|
+
// Exit 2 = BLOCK. Write to both stdout and stderr for visibility.
|
|
547
|
+
const msg = 'SOLONGATE BLOCKED: ' + threat;
|
|
548
|
+
process.stdout.write(msg);
|
|
549
|
+
process.stderr.write(msg);
|
|
544
550
|
process.exit(2);
|
|
545
551
|
}
|
|
546
552
|
} catch {
|
package/dist/init.js
CHANGED
|
@@ -191,20 +191,27 @@ const DANGEROUS_COMMANDS = [
|
|
|
191
191
|
/\\bgit\\s+reset\\s+--hard\\b/i,
|
|
192
192
|
];
|
|
193
193
|
|
|
194
|
-
function
|
|
194
|
+
function checkPath(val) {
|
|
195
195
|
if (typeof val !== 'string' || val.length < 2) return null;
|
|
196
196
|
for (const p of PATH_TRAVERSAL) if (p.test(val)) return 'Path traversal detected';
|
|
197
197
|
for (const p of SENSITIVE_PATHS) if (p.test(val)) return 'Sensitive file access blocked';
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function checkValue(val) {
|
|
202
|
+
if (typeof val !== 'string' || val.length < 2) return null;
|
|
198
203
|
for (const p of SSRF) if (p.test(val)) return 'SSRF attempt blocked';
|
|
199
204
|
for (const p of SQL_INJECTION) if (p.test(val)) return 'SQL injection detected';
|
|
200
205
|
if (val.length > 10000) return 'Input too long (max 10000 chars)';
|
|
201
206
|
return null;
|
|
202
207
|
}
|
|
203
208
|
|
|
209
|
+
// Arguments that contain file paths
|
|
210
|
+
const PATH_ARGS = ['file_path', 'path', 'pattern', 'directory', 'url', 'uri', 'notebook_path'];
|
|
211
|
+
|
|
204
212
|
function checkBashCommand(cmd) {
|
|
205
213
|
if (typeof cmd !== 'string') return null;
|
|
206
214
|
for (const p of DANGEROUS_COMMANDS) if (p.test(cmd)) return 'Dangerous command blocked: ' + cmd.slice(0, 80);
|
|
207
|
-
for (const p of SHELL_INJECTION) if (p.test(cmd)) return null; // shell injection is normal for Bash
|
|
208
215
|
return null;
|
|
209
216
|
}
|
|
210
217
|
|
|
@@ -224,20 +231,17 @@ process.stdin.on('end', async () => {
|
|
|
224
231
|
threat = checkBashCommand(args.command);
|
|
225
232
|
}
|
|
226
233
|
|
|
227
|
-
// Check
|
|
234
|
+
// Check arguments based on type
|
|
228
235
|
if (!threat) {
|
|
229
236
|
for (const [key, val] of Object.entries(args)) {
|
|
230
|
-
if (tool === 'Bash' && key === 'command') continue;
|
|
231
|
-
|
|
232
|
-
if (
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
threat = checkValue(v);
|
|
237
|
-
if (threat) { threat = threat + ' (in ' + key + ')'; break; }
|
|
238
|
-
}
|
|
239
|
-
if (threat) break;
|
|
237
|
+
if (tool === 'Bash' && key === 'command') continue;
|
|
238
|
+
if (key === 'content' || key === 'new_source' || key === 'new_string' || key === 'old_string' || key === 'description') continue;
|
|
239
|
+
if (PATH_ARGS.includes(key)) {
|
|
240
|
+
threat = checkPath(val);
|
|
241
|
+
} else {
|
|
242
|
+
threat = checkValue(val);
|
|
240
243
|
}
|
|
244
|
+
if (threat) { threat = threat + ' (in ' + key + ')'; break; }
|
|
241
245
|
}
|
|
242
246
|
}
|
|
243
247
|
|
|
@@ -258,8 +262,10 @@ process.stdin.on('end', async () => {
|
|
|
258
262
|
signal: AbortSignal.timeout(5000),
|
|
259
263
|
}).catch(() => {});
|
|
260
264
|
}
|
|
261
|
-
// Exit 2 = BLOCK.
|
|
262
|
-
|
|
265
|
+
// Exit 2 = BLOCK. Write to both stdout and stderr for visibility.
|
|
266
|
+
const msg = 'SOLONGATE BLOCKED: ' + threat;
|
|
267
|
+
process.stdout.write(msg);
|
|
268
|
+
process.stderr.write(msg);
|
|
263
269
|
process.exit(2);
|
|
264
270
|
}
|
|
265
271
|
} catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "MCP security proxy \u00e2\u20ac\u201d protect any MCP server with policies, input validation, rate limiting, and audit logging. Zero code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|