@node9/proxy 1.0.3 → 1.0.4

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
@@ -350,6 +350,23 @@ function extractShellCommand(toolName, args, toolInspection) {
350
350
  const value = getNestedValue(args, fieldPath);
351
351
  return typeof value === "string" ? value : null;
352
352
  }
353
+ function isSqlTool(toolName, toolInspection) {
354
+ const patterns = Object.keys(toolInspection);
355
+ const matchingPattern = patterns.find((p) => matchesPattern(toolName, p));
356
+ if (!matchingPattern) return false;
357
+ const fieldName = toolInspection[matchingPattern];
358
+ return fieldName === "sql" || fieldName === "query";
359
+ }
360
+ var SQL_DML_KEYWORDS = /* @__PURE__ */ new Set(["select", "insert", "update", "delete", "merge", "upsert"]);
361
+ function checkDangerousSql(sql) {
362
+ const norm = sql.replace(/\s+/g, " ").trim().toLowerCase();
363
+ const hasWhere = /\bwhere\b/.test(norm);
364
+ if (/^delete\s+from\s+\S+/.test(norm) && !hasWhere)
365
+ return "DELETE without WHERE \u2014 full table wipe";
366
+ if (/^update\s+\S+\s+set\s+/.test(norm) && !hasWhere)
367
+ return "UPDATE without WHERE \u2014 updates every row";
368
+ return null;
369
+ }
353
370
  async function analyzeShellCommand(command) {
354
371
  const actions = [];
355
372
  const paths = [];
@@ -529,9 +546,20 @@ async function evaluatePolicy(toolName, args, agent) {
529
546
  if (INLINE_EXEC_PATTERN.test(shellCommand.trim())) {
530
547
  return { decision: "review", blockedByLabel: "Node9 Standard (Inline Execution)" };
531
548
  }
549
+ if (isSqlTool(toolName, config.policy.toolInspection)) {
550
+ const sqlDanger = checkDangerousSql(shellCommand);
551
+ if (sqlDanger) return { decision: "review", blockedByLabel: `SQL Safety: ${sqlDanger}` };
552
+ allTokens = allTokens.filter((t) => !SQL_DML_KEYWORDS.has(t.toLowerCase()));
553
+ actionTokens = actionTokens.filter((t) => !SQL_DML_KEYWORDS.has(t.toLowerCase()));
554
+ }
532
555
  } else {
533
556
  allTokens = tokenize(toolName);
534
557
  actionTokens = [toolName];
558
+ if (args && typeof args === "object") {
559
+ const flattenedArgs = JSON.stringify(args).toLowerCase();
560
+ const extraTokens = flattenedArgs.split(/[^a-zA-Z0-9]+/).filter((t) => t.length > 1);
561
+ allTokens.push(...extraTokens);
562
+ }
535
563
  }
536
564
  const isManual = agent === "Terminal";
537
565
  if (isManual) {
package/dist/index.mjs CHANGED
@@ -314,6 +314,23 @@ function extractShellCommand(toolName, args, toolInspection) {
314
314
  const value = getNestedValue(args, fieldPath);
315
315
  return typeof value === "string" ? value : null;
316
316
  }
317
+ function isSqlTool(toolName, toolInspection) {
318
+ const patterns = Object.keys(toolInspection);
319
+ const matchingPattern = patterns.find((p) => matchesPattern(toolName, p));
320
+ if (!matchingPattern) return false;
321
+ const fieldName = toolInspection[matchingPattern];
322
+ return fieldName === "sql" || fieldName === "query";
323
+ }
324
+ var SQL_DML_KEYWORDS = /* @__PURE__ */ new Set(["select", "insert", "update", "delete", "merge", "upsert"]);
325
+ function checkDangerousSql(sql) {
326
+ const norm = sql.replace(/\s+/g, " ").trim().toLowerCase();
327
+ const hasWhere = /\bwhere\b/.test(norm);
328
+ if (/^delete\s+from\s+\S+/.test(norm) && !hasWhere)
329
+ return "DELETE without WHERE \u2014 full table wipe";
330
+ if (/^update\s+\S+\s+set\s+/.test(norm) && !hasWhere)
331
+ return "UPDATE without WHERE \u2014 updates every row";
332
+ return null;
333
+ }
317
334
  async function analyzeShellCommand(command) {
318
335
  const actions = [];
319
336
  const paths = [];
@@ -493,9 +510,20 @@ async function evaluatePolicy(toolName, args, agent) {
493
510
  if (INLINE_EXEC_PATTERN.test(shellCommand.trim())) {
494
511
  return { decision: "review", blockedByLabel: "Node9 Standard (Inline Execution)" };
495
512
  }
513
+ if (isSqlTool(toolName, config.policy.toolInspection)) {
514
+ const sqlDanger = checkDangerousSql(shellCommand);
515
+ if (sqlDanger) return { decision: "review", blockedByLabel: `SQL Safety: ${sqlDanger}` };
516
+ allTokens = allTokens.filter((t) => !SQL_DML_KEYWORDS.has(t.toLowerCase()));
517
+ actionTokens = actionTokens.filter((t) => !SQL_DML_KEYWORDS.has(t.toLowerCase()));
518
+ }
496
519
  } else {
497
520
  allTokens = tokenize(toolName);
498
521
  actionTokens = [toolName];
522
+ if (args && typeof args === "object") {
523
+ const flattenedArgs = JSON.stringify(args).toLowerCase();
524
+ const extraTokens = flattenedArgs.split(/[^a-zA-Z0-9]+/).filter((t) => t.length > 1);
525
+ allTokens.push(...extraTokens);
526
+ }
499
527
  }
500
528
  const isManual = agent === "Terminal";
501
529
  if (isManual) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node9/proxy",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "The Sudo Command for AI Agents. Execution Security for Claude Code & MCP.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",