@solongate/proxy 0.38.0 → 0.39.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.
- package/dist/index.js +21 -0
- package/dist/lib.js +21 -0
- package/hooks/guard.mjs +26 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5707,6 +5707,27 @@ var AiJudge = class _AiJudge {
|
|
|
5707
5707
|
}
|
|
5708
5708
|
this.consecutiveFailures = 0;
|
|
5709
5709
|
}
|
|
5710
|
+
const argStr = JSON.stringify(args).toLowerCase();
|
|
5711
|
+
const hasShellTricks = /\$[\({]|`|<\(|>\(|\beval\b|\bexec\b|\bsource\b|\bxargs\b/.test(argStr);
|
|
5712
|
+
const hasWildcard = /[*?]/.test(argStr);
|
|
5713
|
+
let couldMatchProtected = hasShellTricks || hasWildcard;
|
|
5714
|
+
if (!couldMatchProtected) {
|
|
5715
|
+
const allProtected = [...this.protectedFiles, ...this.protectedPaths];
|
|
5716
|
+
for (const p of allProtected) {
|
|
5717
|
+
const core = p.replace(/[*?[\]{}]/g, "").replace(/^\.+/, "").toLowerCase();
|
|
5718
|
+
if (core && core.length >= 2 && argStr.includes(core)) {
|
|
5719
|
+
couldMatchProtected = true;
|
|
5720
|
+
break;
|
|
5721
|
+
}
|
|
5722
|
+
}
|
|
5723
|
+
}
|
|
5724
|
+
if (!couldMatchProtected) {
|
|
5725
|
+
return {
|
|
5726
|
+
decision: "ALLOW",
|
|
5727
|
+
reason: "No protected file/path referenced in arguments",
|
|
5728
|
+
confidence: 1
|
|
5729
|
+
};
|
|
5730
|
+
}
|
|
5710
5731
|
const sanitizedArgs = this.sanitizeArgs(args);
|
|
5711
5732
|
const userMessage = JSON.stringify({
|
|
5712
5733
|
tool: toolName,
|
package/dist/lib.js
CHANGED
|
@@ -4006,6 +4006,27 @@ var AiJudge = class _AiJudge {
|
|
|
4006
4006
|
}
|
|
4007
4007
|
this.consecutiveFailures = 0;
|
|
4008
4008
|
}
|
|
4009
|
+
const argStr = JSON.stringify(args).toLowerCase();
|
|
4010
|
+
const hasShellTricks = /\$[\({]|`|<\(|>\(|\beval\b|\bexec\b|\bsource\b|\bxargs\b/.test(argStr);
|
|
4011
|
+
const hasWildcard = /[*?]/.test(argStr);
|
|
4012
|
+
let couldMatchProtected = hasShellTricks || hasWildcard;
|
|
4013
|
+
if (!couldMatchProtected) {
|
|
4014
|
+
const allProtected = [...this.protectedFiles, ...this.protectedPaths];
|
|
4015
|
+
for (const p of allProtected) {
|
|
4016
|
+
const core = p.replace(/[*?[\]{}]/g, "").replace(/^\.+/, "").toLowerCase();
|
|
4017
|
+
if (core && core.length >= 2 && argStr.includes(core)) {
|
|
4018
|
+
couldMatchProtected = true;
|
|
4019
|
+
break;
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4022
|
+
}
|
|
4023
|
+
if (!couldMatchProtected) {
|
|
4024
|
+
return {
|
|
4025
|
+
decision: "ALLOW",
|
|
4026
|
+
reason: "No protected file/path referenced in arguments",
|
|
4027
|
+
confidence: 1
|
|
4028
|
+
};
|
|
4029
|
+
}
|
|
4009
4030
|
const sanitizedArgs = this.sanitizeArgs(args);
|
|
4010
4031
|
const userMessage = JSON.stringify({
|
|
4011
4032
|
tool: toolName,
|
package/hooks/guard.mjs
CHANGED
|
@@ -1194,6 +1194,30 @@ process.stdin.on('end', async () => {
|
|
|
1194
1194
|
}
|
|
1195
1195
|
}
|
|
1196
1196
|
|
|
1197
|
+
// Pre-filter: skip AI Judge if tool args clearly don't touch any protected file/path.
|
|
1198
|
+
// Only call LLM when there's a potential match or obfuscation attempt.
|
|
1199
|
+
const argStr = JSON.stringify(args).toLowerCase();
|
|
1200
|
+
const hasShellTricks = /\$[\({]|`|<\(|>\(|\beval\b|\bexec\b|\bsource\b|\bxargs\b/.test(argStr);
|
|
1201
|
+
const hasWildcard = /[*?]/.test(argStr);
|
|
1202
|
+
let couldMatchProtected = hasShellTricks || hasWildcard;
|
|
1203
|
+
if (!couldMatchProtected) {
|
|
1204
|
+
// Check if any protected file/path name (without glob chars) appears in args
|
|
1205
|
+
const allProtected = [...protectedFiles, ...protectedPathsList];
|
|
1206
|
+
for (const p of allProtected) {
|
|
1207
|
+
// Strip glob chars to get the core name: "*.env*" → "env", ".solongate" → "solongate"
|
|
1208
|
+
const core = p.replace(/[*?[\]{}]/g, '').replace(/^\.+/, '').toLowerCase();
|
|
1209
|
+
if (core && core.length >= 2 && argStr.includes(core)) {
|
|
1210
|
+
couldMatchProtected = true;
|
|
1211
|
+
break;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
// If args clearly don't reference any protected pattern, skip LLM — instant ALLOW
|
|
1217
|
+
if (!couldMatchProtected) {
|
|
1218
|
+
// No need to call AI Judge — nothing to protect here
|
|
1219
|
+
} else {
|
|
1220
|
+
|
|
1197
1221
|
const judgePayload = JSON.stringify({
|
|
1198
1222
|
tool: toolName,
|
|
1199
1223
|
arguments: args,
|
|
@@ -1262,6 +1286,8 @@ Respond with ONLY valid JSON: {"decision": "ALLOW" or "DENY", "reason": "brief e
|
|
|
1262
1286
|
}
|
|
1263
1287
|
// Auth/config errors (401, 403) → skip AI Judge, don't DENY
|
|
1264
1288
|
// Other LLM errors → skip too (policy engine already evaluated)
|
|
1289
|
+
|
|
1290
|
+
} // end else (couldMatchProtected)
|
|
1265
1291
|
} catch {
|
|
1266
1292
|
// Timeout or parse error → skip AI Judge (policy engine already passed)
|
|
1267
1293
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.0",
|
|
4
4
|
"description": "AI tool security proxy — protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. Zero code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|