@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.
Files changed (3) hide show
  1. package/dist/index.js +21 -15
  2. package/dist/init.js +21 -15
  3. 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 checkValue(val) {
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 all string arguments for injection patterns
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; // already checked
512
- threat = checkValue(val);
513
- if (threat) { threat = threat + ' (in ' + key + ')'; break; }
514
- // Check nested strings
515
- if (typeof val === 'object' && val) {
516
- for (const v of Object.values(val)) {
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. Message printed to stdout is shown to user.
543
- process.stdout.write('SolonGate BLOCKED: ' + threat);
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 checkValue(val) {
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 all string arguments for injection patterns
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; // already checked
231
- threat = checkValue(val);
232
- if (threat) { threat = threat + ' (in ' + key + ')'; break; }
233
- // Check nested strings
234
- if (typeof val === 'object' && val) {
235
- for (const v of Object.values(val)) {
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. Message printed to stdout is shown to user.
262
- process.stdout.write('SolonGate BLOCKED: ' + threat);
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",
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": {