@node9/proxy 1.36.0 → 1.38.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/cli.js +2181 -614
- package/dist/cli.mjs +2171 -604
- package/dist/dashboard.mjs +6 -0
- package/dist/index.js +42 -0
- package/dist/index.mjs +42 -0
- package/package.json +3 -2
package/dist/dashboard.mjs
CHANGED
|
@@ -2301,6 +2301,11 @@ var init_config_schema = __esm({
|
|
|
2301
2301
|
threshold: z.number().min(2).optional(),
|
|
2302
2302
|
windowSeconds: z.number().min(10).optional()
|
|
2303
2303
|
}).optional(),
|
|
2304
|
+
injectionScan: z.object({
|
|
2305
|
+
enabled: z.boolean().optional(),
|
|
2306
|
+
minConfidence: z.enum(["medium", "high"]).optional(),
|
|
2307
|
+
allow: z.array(z.string()).optional()
|
|
2308
|
+
}).optional(),
|
|
2304
2309
|
skillPinning: z.object({
|
|
2305
2310
|
enabled: z.boolean().optional(),
|
|
2306
2311
|
mode: z.enum(["warn", "block"]).optional(),
|
|
@@ -2602,6 +2607,7 @@ var init_config = __esm({
|
|
|
2602
2607
|
dlp: { enabled: true, scanIgnoredTools: true, pii: "off" },
|
|
2603
2608
|
egress: { enabled: false, mode: "review", allow: [], deny: [], allowPrivate: true },
|
|
2604
2609
|
loopDetection: { enabled: true, threshold: 5, windowSeconds: 120 },
|
|
2610
|
+
injectionScan: { enabled: false, minConfidence: "medium", allow: [] },
|
|
2605
2611
|
skillPinning: { enabled: false, mode: "warn", roots: [] }
|
|
2606
2612
|
},
|
|
2607
2613
|
environments: {}
|
package/dist/index.js
CHANGED
|
@@ -314,6 +314,11 @@ var ConfigFileSchema = import_zod.z.object({
|
|
|
314
314
|
threshold: import_zod.z.number().min(2).optional(),
|
|
315
315
|
windowSeconds: import_zod.z.number().min(10).optional()
|
|
316
316
|
}).optional(),
|
|
317
|
+
injectionScan: import_zod.z.object({
|
|
318
|
+
enabled: import_zod.z.boolean().optional(),
|
|
319
|
+
minConfidence: import_zod.z.enum(["medium", "high"]).optional(),
|
|
320
|
+
allow: import_zod.z.array(import_zod.z.string()).optional()
|
|
321
|
+
}).optional(),
|
|
317
322
|
skillPinning: import_zod.z.object({
|
|
318
323
|
enabled: import_zod.z.boolean().optional(),
|
|
319
324
|
mode: import_zod.z.enum(["warn", "block"]).optional(),
|
|
@@ -3570,6 +3575,7 @@ var DEFAULT_CONFIG = {
|
|
|
3570
3575
|
dlp: { enabled: true, scanIgnoredTools: true, pii: "off" },
|
|
3571
3576
|
egress: { enabled: false, mode: "review", allow: [], deny: [], allowPrivate: true },
|
|
3572
3577
|
loopDetection: { enabled: true, threshold: 5, windowSeconds: 120 },
|
|
3578
|
+
injectionScan: { enabled: false, minConfidence: "medium", allow: [] },
|
|
3573
3579
|
skillPinning: { enabled: false, mode: "warn", roots: [] }
|
|
3574
3580
|
},
|
|
3575
3581
|
environments: {}
|
|
@@ -3700,6 +3706,10 @@ function getConfig(cwd) {
|
|
|
3700
3706
|
deny: [...DEFAULT_CONFIG.policy.egress.deny]
|
|
3701
3707
|
},
|
|
3702
3708
|
loopDetection: { ...DEFAULT_CONFIG.policy.loopDetection },
|
|
3709
|
+
injectionScan: {
|
|
3710
|
+
...DEFAULT_CONFIG.policy.injectionScan,
|
|
3711
|
+
allow: [...DEFAULT_CONFIG.policy.injectionScan.allow]
|
|
3712
|
+
},
|
|
3703
3713
|
skillPinning: {
|
|
3704
3714
|
...DEFAULT_CONFIG.policy.skillPinning,
|
|
3705
3715
|
roots: [...DEFAULT_CONFIG.policy.skillPinning.roots]
|
|
@@ -3766,6 +3776,17 @@ function getConfig(cwd) {
|
|
|
3766
3776
|
if (ld.windowSeconds !== void 0)
|
|
3767
3777
|
mergedPolicy.loopDetection.windowSeconds = ld.windowSeconds;
|
|
3768
3778
|
}
|
|
3779
|
+
if (p.injectionScan && typeof p.injectionScan === "object") {
|
|
3780
|
+
const is = p.injectionScan;
|
|
3781
|
+
if (is.enabled !== void 0) mergedPolicy.injectionScan.enabled = is.enabled;
|
|
3782
|
+
if (is.minConfidence !== void 0)
|
|
3783
|
+
mergedPolicy.injectionScan.minConfidence = is.minConfidence;
|
|
3784
|
+
if (Array.isArray(is.allow)) {
|
|
3785
|
+
for (const t of is.allow) {
|
|
3786
|
+
if (typeof t === "string" && t.length > 0) mergedPolicy.injectionScan.allow.push(t);
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3789
|
+
}
|
|
3769
3790
|
if (p.skillPinning && typeof p.skillPinning === "object") {
|
|
3770
3791
|
const sp = p.skillPinning;
|
|
3771
3792
|
if (sp.enabled !== void 0) mergedPolicy.skillPinning.enabled = sp.enabled;
|
|
@@ -4377,6 +4398,21 @@ async function checkTaint(paths) {
|
|
|
4377
4398
|
return { tainted: false, daemonUnavailable: true };
|
|
4378
4399
|
}
|
|
4379
4400
|
}
|
|
4401
|
+
async function checkSessionTaint(sessionId) {
|
|
4402
|
+
if (!sessionId || !isDaemonRunning()) return { tainted: false };
|
|
4403
|
+
const base = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
4404
|
+
try {
|
|
4405
|
+
const res = await fetch(`${base}/session-taint/check`, {
|
|
4406
|
+
method: "POST",
|
|
4407
|
+
headers: { "Content-Type": "application/json" },
|
|
4408
|
+
body: JSON.stringify({ sessionId }),
|
|
4409
|
+
signal: AbortSignal.timeout(2e3)
|
|
4410
|
+
});
|
|
4411
|
+
return await res.json();
|
|
4412
|
+
} catch {
|
|
4413
|
+
return { tainted: false, daemonUnavailable: true };
|
|
4414
|
+
}
|
|
4415
|
+
}
|
|
4380
4416
|
async function resolveViaDaemon(id, decision, internalToken, source) {
|
|
4381
4417
|
const base = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
4382
4418
|
await fetch(`${base}/resolve/${id}`, {
|
|
@@ -5056,6 +5092,12 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
5056
5092
|
}
|
|
5057
5093
|
}
|
|
5058
5094
|
}
|
|
5095
|
+
if (!taintWarning && meta?.sessionId && (isNetworkTool(toolName, args) || isWriteTool(toolName))) {
|
|
5096
|
+
const sessionTaint = await checkSessionTaint(meta.sessionId);
|
|
5097
|
+
if (sessionTaint.tainted && sessionTaint.record) {
|
|
5098
|
+
taintWarning = `\u26A0\uFE0F node9 flagged this session \u2014 earlier tool output contained ${sessionTaint.record.source}. Approve this ${isWriteTool(toolName) ? "write" : "network"} action before it proceeds.`;
|
|
5099
|
+
}
|
|
5100
|
+
}
|
|
5059
5101
|
if (config.policy.dlp.enabled && (!isIgnoredTool2(toolName) || config.policy.dlp.scanIgnoredTools)) {
|
|
5060
5102
|
const argsObj = args && typeof args === "object" && !Array.isArray(args) ? args : {};
|
|
5061
5103
|
const filePath = String(argsObj.file_path ?? argsObj.path ?? argsObj.filename ?? "");
|
package/dist/index.mjs
CHANGED
|
@@ -284,6 +284,11 @@ var ConfigFileSchema = z.object({
|
|
|
284
284
|
threshold: z.number().min(2).optional(),
|
|
285
285
|
windowSeconds: z.number().min(10).optional()
|
|
286
286
|
}).optional(),
|
|
287
|
+
injectionScan: z.object({
|
|
288
|
+
enabled: z.boolean().optional(),
|
|
289
|
+
minConfidence: z.enum(["medium", "high"]).optional(),
|
|
290
|
+
allow: z.array(z.string()).optional()
|
|
291
|
+
}).optional(),
|
|
287
292
|
skillPinning: z.object({
|
|
288
293
|
enabled: z.boolean().optional(),
|
|
289
294
|
mode: z.enum(["warn", "block"]).optional(),
|
|
@@ -3540,6 +3545,7 @@ var DEFAULT_CONFIG = {
|
|
|
3540
3545
|
dlp: { enabled: true, scanIgnoredTools: true, pii: "off" },
|
|
3541
3546
|
egress: { enabled: false, mode: "review", allow: [], deny: [], allowPrivate: true },
|
|
3542
3547
|
loopDetection: { enabled: true, threshold: 5, windowSeconds: 120 },
|
|
3548
|
+
injectionScan: { enabled: false, minConfidence: "medium", allow: [] },
|
|
3543
3549
|
skillPinning: { enabled: false, mode: "warn", roots: [] }
|
|
3544
3550
|
},
|
|
3545
3551
|
environments: {}
|
|
@@ -3670,6 +3676,10 @@ function getConfig(cwd) {
|
|
|
3670
3676
|
deny: [...DEFAULT_CONFIG.policy.egress.deny]
|
|
3671
3677
|
},
|
|
3672
3678
|
loopDetection: { ...DEFAULT_CONFIG.policy.loopDetection },
|
|
3679
|
+
injectionScan: {
|
|
3680
|
+
...DEFAULT_CONFIG.policy.injectionScan,
|
|
3681
|
+
allow: [...DEFAULT_CONFIG.policy.injectionScan.allow]
|
|
3682
|
+
},
|
|
3673
3683
|
skillPinning: {
|
|
3674
3684
|
...DEFAULT_CONFIG.policy.skillPinning,
|
|
3675
3685
|
roots: [...DEFAULT_CONFIG.policy.skillPinning.roots]
|
|
@@ -3736,6 +3746,17 @@ function getConfig(cwd) {
|
|
|
3736
3746
|
if (ld.windowSeconds !== void 0)
|
|
3737
3747
|
mergedPolicy.loopDetection.windowSeconds = ld.windowSeconds;
|
|
3738
3748
|
}
|
|
3749
|
+
if (p.injectionScan && typeof p.injectionScan === "object") {
|
|
3750
|
+
const is = p.injectionScan;
|
|
3751
|
+
if (is.enabled !== void 0) mergedPolicy.injectionScan.enabled = is.enabled;
|
|
3752
|
+
if (is.minConfidence !== void 0)
|
|
3753
|
+
mergedPolicy.injectionScan.minConfidence = is.minConfidence;
|
|
3754
|
+
if (Array.isArray(is.allow)) {
|
|
3755
|
+
for (const t of is.allow) {
|
|
3756
|
+
if (typeof t === "string" && t.length > 0) mergedPolicy.injectionScan.allow.push(t);
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
}
|
|
3739
3760
|
if (p.skillPinning && typeof p.skillPinning === "object") {
|
|
3740
3761
|
const sp = p.skillPinning;
|
|
3741
3762
|
if (sp.enabled !== void 0) mergedPolicy.skillPinning.enabled = sp.enabled;
|
|
@@ -4347,6 +4368,21 @@ async function checkTaint(paths) {
|
|
|
4347
4368
|
return { tainted: false, daemonUnavailable: true };
|
|
4348
4369
|
}
|
|
4349
4370
|
}
|
|
4371
|
+
async function checkSessionTaint(sessionId) {
|
|
4372
|
+
if (!sessionId || !isDaemonRunning()) return { tainted: false };
|
|
4373
|
+
const base = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
4374
|
+
try {
|
|
4375
|
+
const res = await fetch(`${base}/session-taint/check`, {
|
|
4376
|
+
method: "POST",
|
|
4377
|
+
headers: { "Content-Type": "application/json" },
|
|
4378
|
+
body: JSON.stringify({ sessionId }),
|
|
4379
|
+
signal: AbortSignal.timeout(2e3)
|
|
4380
|
+
});
|
|
4381
|
+
return await res.json();
|
|
4382
|
+
} catch {
|
|
4383
|
+
return { tainted: false, daemonUnavailable: true };
|
|
4384
|
+
}
|
|
4385
|
+
}
|
|
4350
4386
|
async function resolveViaDaemon(id, decision, internalToken, source) {
|
|
4351
4387
|
const base = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
4352
4388
|
await fetch(`${base}/resolve/${id}`, {
|
|
@@ -5026,6 +5062,12 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
5026
5062
|
}
|
|
5027
5063
|
}
|
|
5028
5064
|
}
|
|
5065
|
+
if (!taintWarning && meta?.sessionId && (isNetworkTool(toolName, args) || isWriteTool(toolName))) {
|
|
5066
|
+
const sessionTaint = await checkSessionTaint(meta.sessionId);
|
|
5067
|
+
if (sessionTaint.tainted && sessionTaint.record) {
|
|
5068
|
+
taintWarning = `\u26A0\uFE0F node9 flagged this session \u2014 earlier tool output contained ${sessionTaint.record.source}. Approve this ${isWriteTool(toolName) ? "write" : "network"} action before it proceeds.`;
|
|
5069
|
+
}
|
|
5070
|
+
}
|
|
5029
5071
|
if (config.policy.dlp.enabled && (!isIgnoredTool2(toolName) || config.policy.dlp.scanIgnoredTools)) {
|
|
5030
5072
|
const argsObj = args && typeof args === "object" && !Array.isArray(args) ? args : {};
|
|
5031
5073
|
const filePath = String(argsObj.file_path ?? argsObj.path ?? argsObj.filename ?? "");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node9/proxy",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.38.0",
|
|
4
4
|
"description": "The Sudo Command for AI Agents. Execution Security for Claude Code, Codex, Gemini, Cursor, Opencode, Pi, and any MCP server.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -120,7 +120,8 @@
|
|
|
120
120
|
"vitest": "4.1.2"
|
|
121
121
|
},
|
|
122
122
|
"overrides": {
|
|
123
|
-
"undici": "^7.24.0"
|
|
123
|
+
"undici": "^7.24.0",
|
|
124
|
+
"ws": "^8.21.0"
|
|
124
125
|
},
|
|
125
126
|
"publishConfig": {
|
|
126
127
|
"access": "public"
|