cognium-dev 3.82.0 → 3.84.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/dist/cli.js +271 -7
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -10517,10 +10517,6 @@ var DEFAULT_SINKS = [
10517
10517
  { method: "setCommandline", class: "DefaultExecutor", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
10518
10518
  { method: "parse", class: "CommandLine", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
10519
10519
  { method: "addArgument", class: "CommandLine", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
10520
- { method: "waitFor", class: "Process", type: "command_injection", cwe: "CWE-78", severity: "medium", arg_positions: [] },
10521
- { method: "inheritIO", class: "ProcessBuilder", type: "command_injection", cwe: "CWE-78", severity: "medium", arg_positions: [] },
10522
- { method: "redirectOutput", class: "ProcessBuilder", type: "command_injection", cwe: "CWE-78", severity: "medium", arg_positions: [0] },
10523
- { method: "redirectInput", class: "ProcessBuilder", type: "command_injection", cwe: "CWE-78", severity: "medium", arg_positions: [0] },
10524
10520
  { method: "File", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0, 1] },
10525
10521
  { method: "FileInputStream", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
10526
10522
  { method: "FileOutputStream", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
@@ -10764,7 +10760,6 @@ var DEFAULT_SINKS = [
10764
10760
  { method: "entity", class: "ResponseBuilder", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0] },
10765
10761
  { method: "ok", class: "Response", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0] },
10766
10762
  { method: "eval", class: "ScriptEngine", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
10767
- { method: "compile", class: "Pattern", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0] },
10768
10763
  { method: "parseExpression", class: "ExpressionParser", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
10769
10764
  { method: "parseExpression", class: "SpelExpressionParser", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
10770
10765
  { method: "getValue", class: "Expression", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [] },
@@ -11239,7 +11234,6 @@ var DEFAULT_SINKS = [
11239
11234
  { method: "log", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [1] },
11240
11235
  { method: "exception", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11241
11236
  { method: "command", class: "ProcessBuilder", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
11242
- { method: "inheritIO", class: "ProcessBuilder", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [] },
11243
11237
  { method: "step", class: "StepExecution", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
11244
11238
  { method: "invokeMethod", class: "Script", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
11245
11239
  { method: "evaluate", class: "Script", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
@@ -12053,6 +12047,61 @@ function isSafeGoExecCommandCall(call, pattern, language) {
12053
12047
  return false;
12054
12048
  return true;
12055
12049
  }
12050
+ function isSafeRustCommandCall(call, pattern, language) {
12051
+ if (language !== "rust")
12052
+ return false;
12053
+ if (pattern.type !== "command_injection")
12054
+ return false;
12055
+ if (pattern.class !== undefined && pattern.class !== "Command")
12056
+ return false;
12057
+ const SHELL_PROGRAMS = new Set([
12058
+ "sh",
12059
+ "bash",
12060
+ "zsh",
12061
+ "dash",
12062
+ "ash",
12063
+ "ksh",
12064
+ "cmd",
12065
+ "cmd.exe",
12066
+ "powershell",
12067
+ "pwsh",
12068
+ "powershell.exe",
12069
+ "pwsh.exe"
12070
+ ]);
12071
+ const PROGRAM_RE = /\bCommand\s*::\s*new\s*\(\s*(?:r?"([^"]*)"|'([^']*)')/;
12072
+ const extractProgram = (text) => {
12073
+ const m = PROGRAM_RE.exec(text);
12074
+ if (!m)
12075
+ return null;
12076
+ const lit = m[1] ?? m[2] ?? "";
12077
+ return lit.split("/").pop() ?? lit;
12078
+ };
12079
+ if (pattern.method === "new") {
12080
+ const programArg = call.arguments.find((a) => a.position === 0);
12081
+ if (!programArg)
12082
+ return false;
12083
+ let program;
12084
+ if (programArg.literal !== null && programArg.literal !== undefined) {
12085
+ program = String(programArg.literal).split("/").pop() ?? String(programArg.literal);
12086
+ } else {
12087
+ const expr = (programArg.expression ?? "").trim();
12088
+ if (!(expr.startsWith('"') || expr.startsWith("'"))) {
12089
+ return false;
12090
+ }
12091
+ const stripped = expr.slice(1, -1);
12092
+ program = stripped.split("/").pop() ?? stripped;
12093
+ }
12094
+ return !SHELL_PROGRAMS.has(program);
12095
+ }
12096
+ if (pattern.method === "arg" || pattern.method === "args" || pattern.method === "spawn" || pattern.method === "output") {
12097
+ const receiverText = call.receiver ?? "";
12098
+ const program = extractProgram(receiverText);
12099
+ if (program === null)
12100
+ return false;
12101
+ return !SHELL_PROGRAMS.has(program);
12102
+ }
12103
+ return false;
12104
+ }
12056
12105
  var CLASS_LITERAL_RE = /^(?:[A-Za-z_][\w]*\.)*[A-Z][\w]*(?:\[\])*\.class$/;
12057
12106
  function argIsClassLiteral(call, position) {
12058
12107
  const arg = call.arguments.find((a) => a.position === position);
@@ -12077,6 +12126,9 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
12077
12126
  if (isSafeGoExecCommandCall(call, pattern, language)) {
12078
12127
  continue;
12079
12128
  }
12129
+ if (isSafeRustCommandCall(call, pattern, language)) {
12130
+ continue;
12131
+ }
12080
12132
  if (pattern.safe_if_class_literal_at !== undefined && argIsClassLiteral(call, pattern.safe_if_class_literal_at)) {
12081
12133
  continue;
12082
12134
  }
@@ -21313,6 +21365,14 @@ class LanguageSourcesPass {
21313
21365
  additionalSanitizers.push(...findGoMapAllowlistGuardSanitizers(code));
21314
21366
  additionalSanitizers.push(...findGoHtmlTemplateImportSanitizers(code));
21315
21367
  }
21368
+ if (language === "python") {
21369
+ additionalSanitizers.push(...findPythonNetlocAllowlistGuardSanitizers(code));
21370
+ additionalSanitizers.push(...findPythonRangeCheckGuardSanitizers(code));
21371
+ }
21372
+ if (language === "rust") {
21373
+ additionalSanitizers.push(...findRustSetAllowlistGuardSanitizers(code));
21374
+ additionalSanitizers.push(...findRustCanonicalizeGuardSanitizers(code));
21375
+ }
21316
21376
  attachSourceLineCode(additionalSources, additionalSinks, code);
21317
21377
  return { additionalSources, additionalSinks, additionalSanitizers, pyTaintedVars, pySanitizedVars, jsTaintedVars };
21318
21378
  }
@@ -22427,6 +22487,210 @@ function findGoHtmlTemplateImportSanitizers(code) {
22427
22487
  }
22428
22488
  return sanitizers;
22429
22489
  }
22490
+ function findPythonNetlocAllowlistGuardSanitizers(code) {
22491
+ const sanitizers = [];
22492
+ const lines = code.split(`
22493
+ `);
22494
+ const guardOpen = /^(\s*)if\s+.+?\s+not\s+in\s+([A-Za-z_][A-Za-z0-9_]*)\s*:\s*$/;
22495
+ const allowlistName = /^(?:[A-Z][A-Z0-9_]+|.*?(allowed|accepted|whitelist|permitted|valid|approved).*)$/i;
22496
+ const terminator = /\b(return|raise|abort\s*\(|sys\.exit\s*\()/;
22497
+ for (let i2 = 0;i2 < lines.length; i2++) {
22498
+ const m = guardOpen.exec(lines[i2]);
22499
+ if (!m)
22500
+ continue;
22501
+ const guardIndent = m[1].length;
22502
+ const allowName = m[2];
22503
+ if (!allowlistName.test(allowName))
22504
+ continue;
22505
+ let bodyHasTerminator = false;
22506
+ let blockEnd = -1;
22507
+ const maxScan = Math.min(lines.length, i2 + 26);
22508
+ for (let j = i2 + 1;j < maxScan; j++) {
22509
+ const line = lines[j];
22510
+ if (line.trim() === "")
22511
+ continue;
22512
+ const indent = line.length - line.trimStart().length;
22513
+ if (indent <= guardIndent) {
22514
+ blockEnd = j - 1;
22515
+ break;
22516
+ }
22517
+ if (terminator.test(line))
22518
+ bodyHasTerminator = true;
22519
+ }
22520
+ if (blockEnd === -1)
22521
+ blockEnd = Math.min(lines.length - 1, i2 + 25);
22522
+ if (!bodyHasTerminator)
22523
+ continue;
22524
+ for (let l = blockEnd + 2;l <= lines.length; l++) {
22525
+ sanitizers.push({
22526
+ type: "python_netloc_allowlist_guard",
22527
+ method: "if",
22528
+ line: l,
22529
+ sanitizes: [
22530
+ "open_redirect",
22531
+ "ssrf",
22532
+ "path_traversal",
22533
+ "external_taint_escape"
22534
+ ]
22535
+ });
22536
+ }
22537
+ }
22538
+ return sanitizers;
22539
+ }
22540
+ function findPythonRangeCheckGuardSanitizers(code) {
22541
+ const sanitizers = [];
22542
+ const lines = code.split(`
22543
+ `);
22544
+ const rangeGuard = /^(\s*)if\s+([A-Za-z_][A-Za-z0-9_]*)\s*[<>]=?\s*(?:\d+|-?\d+\.?\d*|[A-Z][A-Z0-9_]+)\s*(?:(?:or|and)\s+\2\s*[<>]=?\s*(?:\d+|-?\d+\.?\d*|[A-Z][A-Z0-9_]+)\s*)?:\s*$/;
22545
+ const terminator = /\b(return|raise|abort\s*\(|sys\.exit\s*\()/;
22546
+ for (let i2 = 0;i2 < lines.length; i2++) {
22547
+ const m = rangeGuard.exec(lines[i2]);
22548
+ if (!m)
22549
+ continue;
22550
+ const guardIndent = m[1].length;
22551
+ let bodyHasTerminator = false;
22552
+ let blockEnd = -1;
22553
+ const maxScan = Math.min(lines.length, i2 + 26);
22554
+ for (let j = i2 + 1;j < maxScan; j++) {
22555
+ const line = lines[j];
22556
+ if (line.trim() === "")
22557
+ continue;
22558
+ const indent = line.length - line.trimStart().length;
22559
+ if (indent <= guardIndent) {
22560
+ blockEnd = j - 1;
22561
+ break;
22562
+ }
22563
+ if (terminator.test(line))
22564
+ bodyHasTerminator = true;
22565
+ }
22566
+ if (blockEnd === -1)
22567
+ blockEnd = Math.min(lines.length - 1, i2 + 25);
22568
+ if (!bodyHasTerminator)
22569
+ continue;
22570
+ for (let l = blockEnd + 2;l <= lines.length; l++) {
22571
+ sanitizers.push({
22572
+ type: "python_range_check_guard",
22573
+ method: "if",
22574
+ line: l,
22575
+ sanitizes: ["xss", "external_taint_escape"]
22576
+ });
22577
+ }
22578
+ }
22579
+ return sanitizers;
22580
+ }
22581
+ function findRustSetAllowlistGuardSanitizers(code) {
22582
+ const sanitizers = [];
22583
+ const lines = code.split(`
22584
+ `);
22585
+ const guardOpen = /^\s*if\s+!\s*([A-Za-z_][A-Za-z0-9_]*)\s*\.\s*(?:contains|contains_key)\s*\(/;
22586
+ const allowlistName = /^(?:[A-Z][A-Z0-9_]+|.*?(allowed|accepted|whitelist|permitted|valid|approved).*)$/i;
22587
+ const terminator = /\b(return|Err\s*\(|panic!\s*\(|HttpResponse::(?:Forbidden|BadRequest|Unauthorized))/;
22588
+ for (let i2 = 0;i2 < lines.length; i2++) {
22589
+ const m = guardOpen.exec(lines[i2]);
22590
+ if (!m)
22591
+ continue;
22592
+ const setName = m[1];
22593
+ if (!allowlistName.test(setName))
22594
+ continue;
22595
+ let depth = 0;
22596
+ for (const ch of lines[i2]) {
22597
+ if (ch === "{")
22598
+ depth++;
22599
+ else if (ch === "}")
22600
+ depth--;
22601
+ }
22602
+ if (depth <= 0)
22603
+ continue;
22604
+ let closeLine = -1;
22605
+ let bodyHasTerminator = false;
22606
+ const maxScan = Math.min(lines.length, i2 + 26);
22607
+ for (let j = i2 + 1;j < maxScan; j++) {
22608
+ const line = lines[j];
22609
+ if (terminator.test(line))
22610
+ bodyHasTerminator = true;
22611
+ for (const ch of line) {
22612
+ if (ch === "{")
22613
+ depth++;
22614
+ else if (ch === "}")
22615
+ depth--;
22616
+ }
22617
+ if (depth === 0) {
22618
+ closeLine = j;
22619
+ break;
22620
+ }
22621
+ }
22622
+ if (closeLine === -1 || !bodyHasTerminator)
22623
+ continue;
22624
+ for (let l = closeLine + 2;l <= lines.length; l++) {
22625
+ sanitizers.push({
22626
+ type: "rust_set_allowlist_guard",
22627
+ method: "if",
22628
+ line: l,
22629
+ sanitizes: [
22630
+ "ssrf",
22631
+ "open_redirect",
22632
+ "command_injection",
22633
+ "external_taint_escape"
22634
+ ]
22635
+ });
22636
+ }
22637
+ }
22638
+ return sanitizers;
22639
+ }
22640
+ function findRustCanonicalizeGuardSanitizers(code) {
22641
+ const sanitizers = [];
22642
+ const lines = code.split(`
22643
+ `);
22644
+ const guardOpen = /^\s*if\s+!\s*[A-Za-z_][\w?.()&]*\.starts_with\s*\(/;
22645
+ const terminator = /\b(return|Err\s*\(|panic!\s*\(|HttpResponse::(?:Forbidden|BadRequest|Unauthorized|NotFound))/;
22646
+ for (let i2 = 0;i2 < lines.length; i2++) {
22647
+ if (!guardOpen.test(lines[i2]))
22648
+ continue;
22649
+ let depth = 0;
22650
+ for (const ch of lines[i2]) {
22651
+ if (ch === "{")
22652
+ depth++;
22653
+ else if (ch === "}")
22654
+ depth--;
22655
+ }
22656
+ if (depth <= 0)
22657
+ continue;
22658
+ let closeLine = -1;
22659
+ let bodyHasTerminator = false;
22660
+ const maxScan = Math.min(lines.length, i2 + 26);
22661
+ for (let j = i2 + 1;j < maxScan; j++) {
22662
+ const line = lines[j];
22663
+ if (terminator.test(line))
22664
+ bodyHasTerminator = true;
22665
+ for (const ch of line) {
22666
+ if (ch === "{")
22667
+ depth++;
22668
+ else if (ch === "}")
22669
+ depth--;
22670
+ }
22671
+ if (depth === 0) {
22672
+ closeLine = j;
22673
+ break;
22674
+ }
22675
+ }
22676
+ if (closeLine === -1 || !bodyHasTerminator)
22677
+ continue;
22678
+ for (let l = closeLine + 2;l <= lines.length; l++) {
22679
+ sanitizers.push({
22680
+ type: "rust_canonicalize_guard",
22681
+ method: "if",
22682
+ line: l,
22683
+ sanitizes: [
22684
+ "path_traversal",
22685
+ "xss",
22686
+ "ssrf",
22687
+ "external_taint_escape"
22688
+ ]
22689
+ });
22690
+ }
22691
+ }
22692
+ return sanitizers;
22693
+ }
22430
22694
 
22431
22695
  // ../circle-ir/dist/analysis/passes/sink-filter-pass.js
22432
22696
  var JS_XSS_SANITIZERS = [
@@ -33592,7 +33856,7 @@ var colors = {
33592
33856
  };
33593
33857
 
33594
33858
  // src/version.ts
33595
- var version = "3.82.0";
33859
+ var version = "3.84.0";
33596
33860
 
33597
33861
  // src/formatters.ts
33598
33862
  var SINK_SEVERITY = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "3.82.0",
3
+ "version": "3.84.0",
4
4
  "description": "Static Application Security Testing CLI for detecting security vulnerabilities via taint tracking",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -65,7 +65,7 @@
65
65
  "registry": "https://registry.npmjs.org/"
66
66
  },
67
67
  "dependencies": {
68
- "circle-ir": "^3.82.0"
68
+ "circle-ir": "^3.84.0"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/node": "^25.5.0",