cognium-dev 3.174.0 → 3.176.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 +159 -8
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -10553,6 +10553,33 @@ var DEFAULT_SOURCES = [
10553
10553
  { method: "decode", class: "JWT", type: "http_header", severity: "high", return_tainted: true, languages: ["java"] },
10554
10554
  { method: "ParseUnverified", class: "jwt", type: "http_header", severity: "high", return_tainted: true, languages: ["go"] }
10555
10555
  ];
10556
+ var OPEN_REDIRECT_FRAMEWORK_SINKS = [
10557
+ { method: "HttpResponseRedirect", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["python"] },
10558
+ { method: "HttpResponsePermanentRedirect", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["python"] },
10559
+ { method: "RedirectResponse", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["python"] },
10560
+ { method: "redirect", class: "Context", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["javascript", "typescript"] },
10561
+ { method: "redirect", class: "FastifyReply", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["javascript", "typescript"] },
10562
+ { method: "location", class: "Response", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["javascript", "typescript"] },
10563
+ { method: "redirect", class: "NextResponse", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["javascript", "typescript"] },
10564
+ { method: "RedirectView", class: "RedirectView", type: "open_redirect", cwe: "CWE-601", severity: "high", arg_positions: [0], languages: ["java"] },
10565
+ { method: "setUrl", class: "RedirectView", type: "open_redirect", cwe: "CWE-601", severity: "high", arg_positions: [0], languages: ["java"] },
10566
+ { method: "seeOther", class: "Response", type: "open_redirect", cwe: "CWE-601", severity: "high", arg_positions: [0], languages: ["java"] },
10567
+ { method: "temporaryRedirect", class: "Response", type: "open_redirect", cwe: "CWE-601", severity: "high", arg_positions: [0], languages: ["java"] },
10568
+ { method: "Redirect", class: "Context", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [1], languages: ["go"] },
10569
+ { method: "Redirect", class: "Ctx", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["go"] }
10570
+ ];
10571
+ var TRUST_BOUNDARY_FRAMEWORK_SINKS = [
10572
+ { method: "set", class: "cache", type: "trust_boundary", cwe: "CWE-501", severity: "medium", arg_positions: [1], languages: ["python"] },
10573
+ { method: "set_many", class: "cache", type: "trust_boundary", cwe: "CWE-501", severity: "medium", arg_positions: [0], languages: ["python"] },
10574
+ { method: "setItem", class: "Storage", type: "trust_boundary", cwe: "CWE-501", severity: "medium", arg_positions: [1], languages: ["javascript", "typescript"] },
10575
+ { method: "cookie", class: "Response", type: "trust_boundary", cwe: "CWE-501", severity: "medium", arg_positions: [1], languages: ["javascript", "typescript"] },
10576
+ { method: "Cookie", class: "Cookie", type: "trust_boundary", cwe: "CWE-501", severity: "medium", arg_positions: [1], languages: ["java"] },
10577
+ { method: "setValue", class: "Cookie", type: "trust_boundary", cwe: "CWE-501", severity: "medium", arg_positions: [0], languages: ["java"] },
10578
+ { method: "setAuthentication", class: "SecurityContext", type: "trust_boundary", cwe: "CWE-501", severity: "high", arg_positions: [0], languages: ["java"] },
10579
+ { method: "setProperty", class: "System", type: "trust_boundary", cwe: "CWE-501", severity: "high", arg_positions: [1], languages: ["java"] },
10580
+ { method: "SetCookie", class: "http", type: "trust_boundary", cwe: "CWE-501", severity: "medium", arg_positions: [1], languages: ["go"] },
10581
+ { method: "SetCookie", class: "Context", type: "trust_boundary", cwe: "CWE-501", severity: "medium", arg_positions: [1], languages: ["go"] }
10582
+ ];
10556
10583
  var DEFAULT_SINKS = [
10557
10584
  { method: "executeQuery", class: "Statement", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
10558
10585
  { method: "execute", class: "Statement", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
@@ -11459,7 +11486,7 @@ var DEFAULT_SINKS = [
11459
11486
  { method: "post", class: "ureq", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
11460
11487
  { method: "parse", class: "Uri", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
11461
11488
  { method: "redirect", class: "HttpResponse", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0] },
11462
- { method: "Redirect", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0] },
11489
+ { method: "Redirect", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["rust"] },
11463
11490
  { method: "see_other", class: "Redirect", type: "open_redirect", cwe: "CWE-601", severity: "high", arg_positions: [0] },
11464
11491
  { method: "to", class: "Redirect", type: "open_redirect", cwe: "CWE-601", severity: "high", arg_positions: [0] },
11465
11492
  { method: "temporary", class: "Redirect", type: "open_redirect", cwe: "CWE-601", severity: "high", arg_positions: [0] },
@@ -11624,7 +11651,9 @@ var DEFAULT_SINKS = [
11624
11651
  { method: "CreateChatCompletionStream", class: "Client", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["go"] },
11625
11652
  { method: "Call", class: "LLM", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["go"] },
11626
11653
  { method: "Generate", class: "LLM", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["go"] },
11627
- { method: "GenerateContent", class: "Model", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["go"] }
11654
+ { method: "GenerateContent", class: "Model", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["go"] },
11655
+ ...OPEN_REDIRECT_FRAMEWORK_SINKS,
11656
+ ...TRUST_BOUNDARY_FRAMEWORK_SINKS
11628
11657
  ];
11629
11658
  var DEFAULT_SANITIZERS = [
11630
11659
  { method: "setString", class: "PreparedStatement", removes: ["sql_injection"] },
@@ -11919,6 +11948,84 @@ var DEFAULT_HEADER_RULES = [
11919
11948
  note: "Fires when the value is not a string literal (likely reflected from request)"
11920
11949
  }
11921
11950
  ];
11951
+ // ../circle-ir/dist/analysis/arg-type-resolver.js
11952
+ function findEnclosingType(callInMethod, types) {
11953
+ if (!callInMethod)
11954
+ return null;
11955
+ for (const t of types) {
11956
+ for (const m of t.methods) {
11957
+ if (m.name === callInMethod)
11958
+ return t;
11959
+ }
11960
+ }
11961
+ return null;
11962
+ }
11963
+ function resolveIdentifierType(name2, callInMethod, types) {
11964
+ if (!name2)
11965
+ return null;
11966
+ const enclosing = findEnclosingType(callInMethod, types);
11967
+ if (enclosing) {
11968
+ for (const m of enclosing.methods) {
11969
+ if (m.name !== callInMethod)
11970
+ continue;
11971
+ for (const p of m.parameters) {
11972
+ if (p.name === name2 && p.type)
11973
+ return p.type;
11974
+ }
11975
+ }
11976
+ for (const f of enclosing.fields) {
11977
+ if (f.name === name2 && f.type)
11978
+ return f.type;
11979
+ }
11980
+ return null;
11981
+ }
11982
+ for (const t of types) {
11983
+ for (const m of t.methods) {
11984
+ for (const p of m.parameters) {
11985
+ if (p.name === name2 && p.type)
11986
+ return p.type;
11987
+ }
11988
+ }
11989
+ for (const f of t.fields) {
11990
+ if (f.name === name2 && f.type)
11991
+ return f.type;
11992
+ }
11993
+ }
11994
+ return null;
11995
+ }
11996
+ function resolveCallReturnType(calleeName, callInMethod, types) {
11997
+ if (!calleeName)
11998
+ return null;
11999
+ const enclosing = findEnclosingType(callInMethod, types);
12000
+ if (enclosing) {
12001
+ for (const m of enclosing.methods) {
12002
+ if (m.name === calleeName && m.return_type)
12003
+ return m.return_type;
12004
+ }
12005
+ }
12006
+ for (const t of types) {
12007
+ for (const m of t.methods) {
12008
+ if (m.name === calleeName && m.return_type)
12009
+ return m.return_type;
12010
+ }
12011
+ }
12012
+ return null;
12013
+ }
12014
+ function isBoundedClassType(rawType) {
12015
+ if (!rawType)
12016
+ return false;
12017
+ const stripped = rawType.trim().replace(/^(?:java\.lang\.)+/, "");
12018
+ return /^Class(?:\s*<[\s\S]*>)?$/.test(stripped);
12019
+ }
12020
+ function isArgvContainerType(rawType) {
12021
+ if (!rawType)
12022
+ return false;
12023
+ const s = rawType.trim().replace(/^(?:java\.util\.|java\.lang\.)+/, "");
12024
+ if (/^String\s*(?:\[\s*\]|\.\.\.)$/.test(s))
12025
+ return true;
12026
+ return /^(?:List|ArrayList|LinkedList|Collection|Iterable|Deque|Queue)\s*<\s*(?:String|CharSequence|java\.lang\.String)\b/.test(s);
12027
+ }
12028
+
11922
12029
  // ../circle-ir/dist/analysis/taint-matcher.js
11923
12030
  var PYTHON_TAINTED_PATTERNS = [
11924
12031
  { pattern: /\brequest\.args\b/, sourceType: "http_param" },
@@ -11942,7 +12049,7 @@ function analyzeTaint(calls, types, config = getDefaultConfig(), typeHierarchy,
11942
12049
  const sources = findSources(calls, types, config.sources, sourceLines, language);
11943
12050
  let sinkPatterns = expandPromisifyAliases(config.sinks, sourceLines, language);
11944
12051
  sinkPatterns = expandIndirectEvalAliases(sinkPatterns, sourceLines, language);
11945
- const sinks = findSinks(calls, sinkPatterns, typeHierarchy, language, sourceLines);
12052
+ const sinks = findSinks(calls, sinkPatterns, typeHierarchy, language, sourceLines, types);
11946
12053
  const sanitizers = findSanitizers(calls, types, config.sanitizers, sourceLines);
11947
12054
  return { sources, sinks, sanitizers };
11948
12055
  }
@@ -12558,7 +12665,7 @@ function isSafeRustCommandCall(call, pattern, language) {
12558
12665
  return false;
12559
12666
  }
12560
12667
  var CLASS_LITERAL_RE = /^(?:[A-Za-z_][\w]*\.)*[A-Z][\w]*(?:\[\])*\.class$/;
12561
- function argIsClassLiteral(call, position) {
12668
+ function argIsClassLiteral(call, position, types) {
12562
12669
  const arg = call.arguments.find((a) => a.position === position);
12563
12670
  if (!arg)
12564
12671
  return false;
@@ -12567,7 +12674,28 @@ function argIsClassLiteral(call, position) {
12567
12674
  return false;
12568
12675
  if (CLASS_LITERAL_RE.test(expr))
12569
12676
  return true;
12570
- return TYPE_TOKEN_RE.test(expr);
12677
+ if (TYPE_TOKEN_RE.test(expr))
12678
+ return true;
12679
+ if (!types || types.length === 0)
12680
+ return false;
12681
+ const argExpr = (arg.expression ?? "").trim();
12682
+ const varName = arg.variable ?? "";
12683
+ const isBareIdentifier = varName !== "" && argExpr === varName && !/[(.]/.test(argExpr);
12684
+ if (isBareIdentifier) {
12685
+ const t = resolveIdentifierType(varName, call.in_method, types);
12686
+ if (isBoundedClassType(t))
12687
+ return true;
12688
+ }
12689
+ const isCallExpr = varName !== "" && new RegExp(`^${escapeRe(varName)}\\s*\\(`).test(argExpr);
12690
+ if (isCallExpr) {
12691
+ const t = resolveCallReturnType(varName, call.in_method, types);
12692
+ if (isBoundedClassType(t))
12693
+ return true;
12694
+ }
12695
+ return false;
12696
+ }
12697
+ function escapeRe(s) {
12698
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
12571
12699
  }
12572
12700
  var TYPE_TOKEN_RE = /^new\s+(?:TypeReference|TypeToken)\s*<[\s\S]*>\s*\(\s*\)\s*\{\s*\}$/;
12573
12701
  function argIsStringLiteral(call, position) {
@@ -12750,7 +12878,7 @@ function isSafeJinjaRenderCall(call, pattern, language, sourceLines) {
12750
12878
  }
12751
12879
  return false;
12752
12880
  }
12753
- function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
12881
+ function findSinks(calls, patterns, typeHierarchy, language, sourceLines, types) {
12754
12882
  const sinkMap = new Map;
12755
12883
  for (const call of calls) {
12756
12884
  for (const pattern of patterns) {
@@ -12770,7 +12898,7 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
12770
12898
  if (isSafeJSChildProcessCall(call, pattern, language)) {
12771
12899
  continue;
12772
12900
  }
12773
- if (pattern.safe_if_class_literal_at !== undefined && argIsClassLiteral(call, pattern.safe_if_class_literal_at)) {
12901
+ if (pattern.safe_if_class_literal_at !== undefined && argIsClassLiteral(call, pattern.safe_if_class_literal_at, types)) {
12774
12902
  continue;
12775
12903
  }
12776
12904
  if (pattern.safe_if_string_literal_at !== undefined && argIsStringLiteral(call, pattern.safe_if_string_literal_at)) {
@@ -30767,6 +30895,9 @@ class MyBatisAnnotationSqlSinkPass {
30767
30895
  }
30768
30896
 
30769
30897
  // ../circle-ir/dist/analysis/passes/sink-filter-pass.js
30898
+ function escapeReSf(s) {
30899
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
30900
+ }
30770
30901
  var JS_XSS_SANITIZERS = [
30771
30902
  /\bDOMPurify\.sanitize\s*\(/,
30772
30903
  /\bsanitizeHtml\s*\(/,
@@ -31396,6 +31527,8 @@ class SinkFilterPass {
31396
31527
  if (language === "java") {
31397
31528
  const sourceLines = ctx.code.split(`
31398
31529
  `);
31530
+ const irCalls = ctx.graph.ir.calls;
31531
+ const irTypes = ctx.graph.ir.types;
31399
31532
  filtered = filtered.filter((sink) => {
31400
31533
  if (sink.type !== "command_injection")
31401
31534
  return true;
@@ -31406,6 +31539,24 @@ class SinkFilterPass {
31406
31539
  return true;
31407
31540
  if (PROCESS_BUILDER_ARGV_FORM_RE.test(sinkLineText))
31408
31541
  return false;
31542
+ const ctorCall = irCalls.find((c) => c.method_name === "ProcessBuilder" && c.location.line === sink.line && (c.receiver === null || c.receiver === undefined));
31543
+ if (!ctorCall || ctorCall.arguments.length === 0)
31544
+ return true;
31545
+ const arg0 = ctorCall.arguments[0];
31546
+ if (!arg0)
31547
+ return true;
31548
+ const argExpr = (arg0.expression ?? "").trim();
31549
+ const varName = arg0.variable ?? "";
31550
+ if (varName !== "" && argExpr === varName && !/[(.]/.test(argExpr)) {
31551
+ const t = resolveIdentifierType(varName, ctorCall.in_method, irTypes);
31552
+ if (isArgvContainerType(t))
31553
+ return false;
31554
+ }
31555
+ if (varName !== "" && new RegExp(`^${escapeReSf(varName)}\\s*\\(`).test(argExpr)) {
31556
+ const t = resolveCallReturnType(varName, ctorCall.in_method, irTypes);
31557
+ if (isArgvContainerType(t))
31558
+ return false;
31559
+ }
31409
31560
  return true;
31410
31561
  });
31411
31562
  }
@@ -44767,7 +44918,7 @@ var colors = {
44767
44918
  };
44768
44919
 
44769
44920
  // src/version.ts
44770
- var version = "3.174.0";
44921
+ var version = "3.176.0";
44771
44922
 
44772
44923
  // src/formatters.ts
44773
44924
  var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "3.174.0",
3
+ "version": "3.176.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",
@@ -66,7 +66,7 @@
66
66
  },
67
67
  "dependencies": {
68
68
  "@cognium/project-profile-detect": "^1.1.0",
69
- "circle-ir": "^3.174.0"
69
+ "circle-ir": "^3.176.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",