@solongate/proxy 0.25.7 → 0.26.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/dist/index.js CHANGED
@@ -6135,45 +6135,37 @@ var PolicySyncManager = class {
6135
6135
  };
6136
6136
 
6137
6137
  // src/ai-judge.ts
6138
- var SYSTEM_PROMPT = `You are a security judge for an MCP (Model Context Protocol) proxy. You evaluate tool calls and decide if they should be ALLOWED or DENIED.
6138
+ var SYSTEM_PROMPT = `You are a security judge for an AI coding tool. You evaluate tool calls and decide if they should be ALLOWED or DENIED.
6139
6139
 
6140
6140
  You will receive a JSON object with:
6141
- - "tool": the MCP tool name being called
6141
+ - "tool": the tool name being called
6142
6142
  - "arguments": the tool's arguments
6143
- - "protected_files": list of files that must NEVER be read, written, copied, moved, or accessed
6144
- - "protected_paths": list of directories/paths that must NEVER be accessed
6143
+ - "protected_files": EXACT list of files that must NEVER be accessed. ONLY these specific files are protected \u2014 nothing else.
6144
+ - "protected_paths": EXACT list of directories that must NEVER be accessed. ONLY these specific paths are protected \u2014 nothing else.
6145
6145
  - "denied_actions": list of actions that are never allowed
6146
6146
 
6147
- DENY if the tool call could, directly or indirectly:
6148
- - Read, display, copy, move, or exfiltrate any protected file \u2014 even through:
6149
- - Shell glob patterns (e.g., "cred*" could match "credentials.json")
6150
- - Command substitution ($(...), backticks)
6151
- - Process substitution (<(cat file), <(command file)) \u2014 ALWAYS check inside <(...) for protected files
6152
- - Variable interpolation or string concatenation (e.g., f=".en"; cat \${f}v builds ".env")
6153
- - Partial variable construction \u2014 if shell variables are concatenated to form a filename, analyze the RESULT
6154
- - Input redirection (< file)
6155
- - Script files that might read protected files
6156
- - Find/exec patterns
6157
- - Multi-stage operations: if command A archives/copies a protected file and command B reads the copy, DENY the ENTIRE chain (e.g., "tar czf /tmp/x.tgz .env && tar xzf /tmp/x.tgz -O")
6158
- - Any Unix/Windows utility that reads file content (cat, head, tail, less, more, type, perl, awk, sed, sort, diff, comm, paste, tee, xxd, od, strings, dd, tr, tar, zip, etc.)
6159
- - Delete, modify, or overwrite any protected file or path
6160
- - Send data to external URLs, webhooks, or attacker-controlled endpoints
6161
- - Execute remotely downloaded code (curl|bash, wget|sh, etc.)
6162
- - Leak environment variables (printenv, env, /proc/self/environ, npm run env, process.env)
6163
- - Create scripts that bypass security controls
6147
+ IMPORTANT: You must ONLY protect files and paths that are EXPLICITLY listed in protected_files and protected_paths. If a file is NOT in the list, it is NOT protected and access should be ALLOWED. Do NOT invent or assume additional protected files.
6164
6148
 
6165
- CRITICAL patterns to watch for:
6166
- - <(cat .env) or <(cat ANYPROTECTEDFILE) \u2014 process substitution ALWAYS reads the file
6167
- - Compound commands with && or ; where ANY part touches a protected file \u2014 DENY the whole thing
6168
- - Variable tricks like f=".en"; cat \${f}v \u2014 mentally evaluate the variable to see if it resolves to a protected filename
6169
- - tar/zip/cp that archives a protected file, even if the second command reads the archive \u2014 DENY both
6149
+ DENY if the tool call could, directly or indirectly, access a file from the protected_files list \u2014 even through:
6150
+ - Shell glob patterns (e.g., "cred*" could match "credentials.json" IF credentials.json is in protected_files)
6151
+ - Command substitution ($(...), backticks)
6152
+ - Process substitution (<(cat file)) \u2014 check inside <(...) for protected files
6153
+ - Variable interpolation (e.g., f=".en"; cat \${f}v builds ".env" \u2014 DENY only if .env is in protected_files)
6154
+ - Input redirection (< file)
6155
+ - Multi-stage operations: tar/cp a protected file then read the copy \u2014 DENY the entire chain
6156
+ - Any utility that reads file content (cat, head, tail, less, perl, awk, sed, xxd, od, strings, dd, etc.)
6157
+
6158
+ Also DENY if:
6159
+ - The command sends data to external URLs (curl -d, wget --post)
6160
+ - The command leaks environment variables (printenv, env, process.env)
6161
+ - The command executes remotely downloaded code (curl|bash)
6170
6162
 
6171
6163
  ALLOW if:
6172
- - The action is a normal development operation (ls, git status, npm build, etc.)
6164
+ - The file is NOT in protected_files \u2014 even if cat, head, etc. is used. Reading non-protected files is normal.
6165
+ - The action is a normal development operation (ls, git status, npm build, cat app.js, etc.)
6173
6166
  - The action does not touch any protected file or path
6174
- - The action is clearly benign (creating hello.js, reading public docs, etc.)
6175
6167
 
6176
- When in doubt, DENY. False positives are acceptable; false negatives are not.
6168
+ CRITICAL: Only DENY access to files EXPLICITLY in the protected_files list. "cat app.js" is ALLOWED if app.js is not in protected_files. Do NOT over-block.
6177
6169
 
6178
6170
  Respond with ONLY valid JSON, no markdown, no explanation outside the JSON:
6179
6171
  {"decision": "ALLOW" or "DENY", "reason": "brief one-line explanation", "confidence": 0.0 to 1.0}`;
package/hooks/guard.mjs CHANGED
@@ -1013,7 +1013,132 @@ process.stdin.on('end', async () => {
1013
1013
  process.exit(0); // No policy = allow all
1014
1014
  }
1015
1015
 
1016
- const reason = evaluate(policy, args);
1016
+ let reason = evaluate(policy, args);
1017
+
1018
+ // ── AI Judge: semantic intent analysis (runs when policy ALLOWs) ──
1019
+ if (!reason) {
1020
+ const GROQ_KEY = process.env.GROQ_API_KEY || dotenv.GROQ_API_KEY || '';
1021
+ let aiJudgeEnabled = false;
1022
+ let aiJudgeModel = 'llama-3.1-8b-instant';
1023
+ let aiJudgeEndpoint = 'https://api.groq.com/openai';
1024
+ let aiJudgeTimeout = 5000;
1025
+
1026
+ // Check cloud config for AI Judge settings
1027
+ if (API_KEY && API_KEY.startsWith('sg_live_')) {
1028
+ try {
1029
+ const cfgRes = await fetch(API_URL + '/api/v1/project-config/ai-judge', {
1030
+ headers: { 'Authorization': 'Bearer ' + API_KEY },
1031
+ signal: AbortSignal.timeout(3000),
1032
+ });
1033
+ if (cfgRes.ok) {
1034
+ const cfg = await cfgRes.json();
1035
+ aiJudgeEnabled = Boolean(cfg.enabled);
1036
+ if (cfg.model) aiJudgeModel = cfg.model;
1037
+ if (cfg.endpoint) aiJudgeEndpoint = cfg.endpoint;
1038
+ if (cfg.timeoutMs) aiJudgeTimeout = cfg.timeoutMs;
1039
+ }
1040
+ } catch {}
1041
+ }
1042
+
1043
+ if (aiJudgeEnabled && GROQ_KEY) {
1044
+ try {
1045
+ // Extract protected files/paths from policy
1046
+ const protectedFiles = [];
1047
+ const protectedPathsList = [];
1048
+ if (policy && policy.rules) {
1049
+ for (const rule of policy.rules) {
1050
+ if (rule.effect === 'DENY' && rule.enabled !== false) {
1051
+ if (rule.filenameConstraints && rule.filenameConstraints.denied) {
1052
+ for (const f of rule.filenameConstraints.denied) protectedFiles.push(f);
1053
+ }
1054
+ if (rule.pathConstraints && rule.pathConstraints.denied) {
1055
+ for (const p of rule.pathConstraints.denied) protectedPathsList.push(p);
1056
+ }
1057
+ }
1058
+ }
1059
+ }
1060
+
1061
+ const judgePayload = JSON.stringify({
1062
+ tool: toolName,
1063
+ arguments: args,
1064
+ protected_files: protectedFiles,
1065
+ protected_paths: protectedPathsList,
1066
+ denied_actions: ['file deletion', 'data exfiltration', 'remote code execution', 'environment variable leak', 'security control bypass'],
1067
+ });
1068
+
1069
+ const systemPrompt = `You are a security judge for an AI coding tool. You evaluate tool calls and decide if they should be ALLOWED or DENIED.
1070
+
1071
+ You will receive a JSON object with:
1072
+ - "tool": the tool name being called (e.g., Bash, Write, Read, Edit)
1073
+ - "arguments": the tool's arguments
1074
+ - "protected_files": EXACT list of files that must NEVER be accessed. ONLY these specific files are protected — nothing else.
1075
+ - "protected_paths": EXACT list of directories that must NEVER be accessed. ONLY these specific paths are protected — nothing else.
1076
+ - "denied_actions": list of actions that are never allowed
1077
+
1078
+ IMPORTANT: You must ONLY protect files and paths that are EXPLICITLY listed in protected_files and protected_paths. If a file is NOT in the list, it is NOT protected and access should be ALLOWED. Do NOT invent or assume additional protected files.
1079
+
1080
+ DENY if the tool call could, directly or indirectly, access a file from the protected_files list — even through:
1081
+ - Shell glob patterns (e.g., "cred*" could match "credentials.json" IF credentials.json is in protected_files)
1082
+ - Command substitution ($(...), backticks)
1083
+ - Process substitution (<(cat file)) — check inside <(...) for protected files
1084
+ - Variable interpolation (e.g., f=".en"; cat \${f}v builds ".env" — DENY only if .env is in protected_files)
1085
+ - Input redirection (< file)
1086
+ - Multi-stage operations: tar/cp a protected file then read the copy — DENY the entire chain
1087
+ - Any utility that reads file content (cat, head, tail, less, perl, awk, sed, xxd, od, strings, dd, etc.)
1088
+
1089
+ Also DENY if:
1090
+ - The command sends data to external URLs (curl -d, wget --post)
1091
+ - The command leaks environment variables (printenv, env, process.env)
1092
+ - The command executes remotely downloaded code (curl|bash)
1093
+
1094
+ ALLOW if:
1095
+ - The file is NOT in protected_files — even if cat, head, etc. is used. Reading non-protected files is normal.
1096
+ - The action is a normal development operation (ls, git status, npm build, cat app.js, etc.)
1097
+ - The action does not touch any protected file or path
1098
+
1099
+ CRITICAL: Only DENY access to files EXPLICITLY in the protected_files list. "cat app.js" is ALLOWED if app.js is not in protected_files. "cat package.json" is ALLOWED if package.json is not in protected_files. Do NOT over-block.
1100
+
1101
+ Respond with ONLY valid JSON: {"decision": "ALLOW" or "DENY", "reason": "brief explanation", "confidence": 0.0 to 1.0}`;
1102
+
1103
+ const llmRes = await fetch(aiJudgeEndpoint + '/v1/chat/completions', {
1104
+ method: 'POST',
1105
+ headers: {
1106
+ 'Content-Type': 'application/json',
1107
+ 'Authorization': 'Bearer ' + GROQ_KEY,
1108
+ },
1109
+ body: JSON.stringify({
1110
+ model: aiJudgeModel,
1111
+ messages: [
1112
+ { role: 'system', content: systemPrompt },
1113
+ { role: 'user', content: judgePayload },
1114
+ ],
1115
+ temperature: 0,
1116
+ max_tokens: 200,
1117
+ }),
1118
+ signal: AbortSignal.timeout(aiJudgeTimeout),
1119
+ });
1120
+
1121
+ if (llmRes.ok) {
1122
+ const llmData = await llmRes.json();
1123
+ const content = llmData.choices?.[0]?.message?.content || '';
1124
+ const jsonMatch = content.match(/\{[\s\S]*\}/);
1125
+ if (jsonMatch) {
1126
+ const verdict = JSON.parse(jsonMatch[0]);
1127
+ if (verdict.decision === 'DENY') {
1128
+ reason = '[AI Judge] ' + (verdict.reason || 'Blocked by semantic analysis');
1129
+ }
1130
+ }
1131
+ } else {
1132
+ // Fail-closed: LLM error → DENY
1133
+ reason = '[AI Judge] LLM endpoint error (fail-closed)';
1134
+ }
1135
+ } catch (err) {
1136
+ // Fail-closed: timeout or parse error → DENY
1137
+ reason = '[AI Judge] ' + (err.message || 'error') + ' (fail-closed)';
1138
+ }
1139
+ }
1140
+ }
1141
+
1017
1142
  const decision = reason ? 'DENY' : 'ALLOW';
1018
1143
 
1019
1144
  // ── Log ALL decisions to SolonGate Cloud ──
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.25.7",
3
+ "version": "0.26.1",
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": {