@solongate/proxy 0.20.0 → 0.21.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.
Files changed (2) hide show
  1. package/hooks/guard.mjs +29 -1
  2. package/package.json +1 -1
package/hooks/guard.mjs CHANGED
@@ -562,6 +562,33 @@ process.stdin.on('end', async () => {
562
562
  await blockSelfProtection('SOLONGATE: Heredoc to interpreter — blocked');
563
563
  }
564
564
 
565
+ // 7-pre3. Command substitution + destructive = BLOCK
566
+ // Catches: rm -rf $(node scan.mjs), rm `node scan.mjs`, rm $(bash scan.sh)
567
+ // Pattern: destructive command + $() or `` containing interpreter call
568
+ const hasDestructive = /\b(?:rm|rmdir|del|unlink|mv|move|rename|shred)\b/i.test(fullCmd);
569
+ const hasCmdSubInterpreter = /\$\(\s*(?:node|bash|sh|python[23]?|perl|ruby)\b/i.test(fullCmd)
570
+ || /`\s*(?:node|bash|sh|python[23]?|perl|ruby)\b/i.test(fullCmd);
571
+ if (hasDestructive && hasCmdSubInterpreter) {
572
+ await blockSelfProtection('SOLONGATE: Command substitution + destructive op — blocked');
573
+ }
574
+
575
+ // 7-pre4. Pipe from interpreter to destructive loop = BLOCK
576
+ // Catches: node scan.mjs | while read d; do rm -rf "$d"; done
577
+ // node scan.mjs | xargs rm -rf
578
+ // bash scan.sh | while read ...
579
+ const pipeFromInterpreter = /\b(?:node|bash|sh|python[23]?|perl|ruby)\s+\S+\s*\|/i;
580
+ if (pipeFromInterpreter.test(fullCmd) && hasDestructive) {
581
+ await blockSelfProtection('SOLONGATE: Pipe from script to destructive command — blocked');
582
+ }
583
+
584
+ // 7-pre5. Script chaining: interpreter + destructive in same command chain
585
+ // Catches: node scan.mjs && rm -rf $(cat /tmp/targets.txt)
586
+ // bash scan.sh; while read d < targets.txt; do rm -rf "$d"; done
587
+ const hasScriptExec = /\b(?:node|bash|sh|python[23]?|perl|ruby)\s+\S+\.\S+/i.test(fullCmd);
588
+ if (hasScriptExec && hasDestructive) {
589
+ await blockSelfProtection('SOLONGATE: Script execution + destructive command in chain — blocked');
590
+ }
591
+
565
592
  // 7a. Inline interpreter execution — TOTAL BLOCK (no content scan needed)
566
593
  // These can construct ANY string at runtime, bypassing all static analysis
567
594
  const blockedInterpreters = [
@@ -583,7 +610,8 @@ process.stdin.on('end', async () => {
583
610
 
584
611
  // 7b. Pipe-to-interpreter — TOTAL BLOCK
585
612
  // Any content piped to an interpreter can construct arbitrary commands at runtime
586
- const pipeToInterpreter = /\|\s*(?:node|bash|sh|python[23]?|perl|ruby|php)\b/i;
613
+ // Also catches: | xargs node, | xargs bash, etc.
614
+ const pipeToInterpreter = /\|\s*(?:xargs\s+)?(?:node|bash|sh|python[23]?|perl|ruby|php)\b/i;
587
615
  if (pipeToInterpreter.test(fullCmd)) {
588
616
  await blockSelfProtection('SOLONGATE: Pipe to interpreter blocked — runtime bypass risk');
589
617
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "MCP security proxy — protect any MCP server with customizable policies, path/command constraints, rate limiting, and audit logging. Zero code changes required.",
5
5
  "type": "module",
6
6
  "bin": {