cognium-dev 3.182.0 → 3.185.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 +169 -3
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -10691,6 +10691,19 @@ var DEFAULT_SOURCES = [
10691
10691
  { method: "getMap", class: "Metadata", type: "http_header", severity: "high", return_tainted: true, languages: ["javascript", "typescript"] },
10692
10692
  { method: "FromIncomingContext", class: "metadata", type: "http_header", severity: "high", return_tainted: true, languages: ["go"] },
10693
10693
  { method: "get", class: "Metadata", type: "http_header", severity: "high", return_tainted: true, languages: ["java"] },
10694
+ { method: "receive_text", class: "WebSocket", type: "network_input", severity: "high", return_tainted: true, languages: ["python"] },
10695
+ { method: "receive_bytes", class: "WebSocket", type: "network_input", severity: "high", return_tainted: true, languages: ["python"] },
10696
+ { method: "receive_json", class: "WebSocket", type: "http_body", severity: "high", return_tainted: true, languages: ["python"] },
10697
+ { method: "receive", class: "WebSocket", type: "network_input", severity: "high", return_tainted: true, languages: ["python"] },
10698
+ { method: "receive_json", type: "http_body", severity: "high", return_tainted: true, languages: ["python"] },
10699
+ { method: "receive_text", type: "network_input", severity: "high", return_tainted: true, languages: ["python"] },
10700
+ { method: "receive_bytes", type: "network_input", severity: "high", return_tainted: true, languages: ["python"] },
10701
+ { method: "ReadMessage", class: "Conn", type: "network_input", severity: "high", return_tainted: true, languages: ["go"] },
10702
+ { method: "NextReader", class: "Conn", type: "network_input", severity: "high", return_tainted: true, languages: ["go"] },
10703
+ { method: "Read", class: "Conn", type: "network_input", severity: "high", return_tainted: true, languages: ["go"] },
10704
+ { annotation: "OnMessage", type: "network_input", severity: "high", param_tainted: true, languages: ["java"] },
10705
+ { annotation: "MessageMapping", type: "http_body", severity: "high", param_tainted: true, languages: ["java"] },
10706
+ { annotation: "SubscribeMapping", type: "http_body", severity: "high", param_tainted: true, languages: ["java"] },
10694
10707
  { method: "get", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
10695
10708
  { method: "hget", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
10696
10709
  { method: "mget", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
@@ -11982,6 +11995,26 @@ var DEFAULT_SANITIZERS = [
11982
11995
  { method: "resolve", class: "Path", removes: ["path_traversal"] },
11983
11996
  { method: "int", removes: ["sql_injection", "command_injection", "xss"] },
11984
11997
  { method: "float", removes: ["sql_injection", "command_injection"] },
11998
+ { method: "quote", class: "urllib.parse", removes: ["ssrf", "open_redirect", "xss", "path_traversal"] },
11999
+ { method: "quote_plus", class: "urllib.parse", removes: ["ssrf", "open_redirect", "xss", "path_traversal"] },
12000
+ { method: "urlencode", class: "urllib.parse", removes: ["ssrf", "open_redirect", "xss"] },
12001
+ { method: "quote_plus", removes: ["ssrf", "open_redirect", "xss", "path_traversal"] },
12002
+ { method: "urlencode", removes: ["ssrf", "open_redirect", "xss"] },
12003
+ { method: "linkify", class: "bleach", removes: ["xss"] },
12004
+ { method: "linkify", removes: ["xss"] },
12005
+ { method: "escape", class: "django.utils.html", removes: ["xss"] },
12006
+ { method: "strip_tags", class: "django.utils.html", removes: ["xss"] },
12007
+ { method: "escape", class: "jinja2", removes: ["xss"] },
12008
+ { method: "escape", class: "flask", removes: ["xss"] },
12009
+ { method: "escape", class: "saxutils", removes: ["xss"] },
12010
+ { method: "escape", class: "xml.sax.saxutils", removes: ["xss"] },
12011
+ { method: "quoteattr", class: "saxutils", removes: ["xss"] },
12012
+ { method: "quoteattr", class: "xml.sax.saxutils", removes: ["xss"] },
12013
+ { method: "escape", class: "re", removes: ["redos", "code_injection"] },
12014
+ { method: "bindparams", removes: ["sql_injection"] },
12015
+ { method: "Identifier", class: "sql", removes: ["sql_injection"] },
12016
+ { method: "Literal", class: "sql", removes: ["sql_injection"] },
12017
+ { method: "Placeholder", class: "sql", removes: ["sql_injection"] },
11985
12018
  { method: "query!", removes: ["sql_injection"] },
11986
12019
  { method: "query_as!", removes: ["sql_injection"] },
11987
12020
  { method: "query_scalar!", removes: ["sql_injection"] },
@@ -13905,7 +13938,13 @@ function matchesSanitizerPattern(call, pattern) {
13905
13938
  return false;
13906
13939
  }
13907
13940
  if (pattern.class) {
13908
- if (!call.receiver || !receiverMightBeClass(call.receiver, pattern.class)) {
13941
+ if (!call.receiver) {
13942
+ const target = call.resolution?.target;
13943
+ const expectedTail = `${pattern.class}.${pattern.method}`;
13944
+ if (target && (target === expectedTail || target.endsWith("." + expectedTail))) {} else {
13945
+ return false;
13946
+ }
13947
+ } else if (!receiverMightBeClass(call.receiver, pattern.class)) {
13909
13948
  return false;
13910
13949
  }
13911
13950
  }
@@ -24688,7 +24727,10 @@ var PYTHON_TAINTED_PATTERNS2 = [
24688
24727
  { pattern: /\bget_query_parameter\s*\(/, type: "http_param" },
24689
24728
  { pattern: /\bget_header_value\s*\(/, type: "http_header" },
24690
24729
  { pattern: /\bget_cookie_value\s*\(/, type: "http_cookie" },
24691
- { pattern: /\binput\s*\(/, type: "io_input" }
24730
+ { pattern: /\binput\s*\(/, type: "io_input" },
24731
+ { pattern: /\.receive_text\s*\(/, type: "network_input" },
24732
+ { pattern: /\.receive_bytes\s*\(/, type: "network_input" },
24733
+ { pattern: /\.receive_json\s*\(/, type: "http_body" }
24692
24734
  ];
24693
24735
 
24694
24736
  class LanguageSourcesPass {
@@ -25332,6 +25374,36 @@ function findJavaScriptAssignmentSources(sourceCode, language) {
25332
25374
  }
25333
25375
  }
25334
25376
  }
25377
+ sources.push(...findJavaScriptCallbackParamSources(sourceCode));
25378
+ return sources;
25379
+ }
25380
+ function findJavaScriptCallbackParamSources(sourceCode) {
25381
+ const sources = [];
25382
+ const CB_EVENT_RE = /\.on\s*\(\s*['"](?:message|text|binary)['"]\s*,\s*(?:async\s+)?(?:function\s*\*?\s*(?:\w+\s*)?\(\s*(\w+)|\(\s*(\w+)\s*(?:[,):]|$)|(\w+)\s*=>)/;
25383
+ const lines = sourceCode.split(`
25384
+ `);
25385
+ for (let i2 = 0;i2 < lines.length; i2++) {
25386
+ const line = lines[i2];
25387
+ const trimmed = line.trimStart();
25388
+ if (trimmed.startsWith("//") || trimmed.startsWith("*"))
25389
+ continue;
25390
+ const m = line.match(CB_EVENT_RE);
25391
+ if (!m)
25392
+ continue;
25393
+ const paramName = m[1] ?? m[2] ?? m[3];
25394
+ if (!paramName)
25395
+ continue;
25396
+ if (paramName === "err" || paramName === "error")
25397
+ continue;
25398
+ sources.push({
25399
+ type: "network_input",
25400
+ location: `WebSocket .on(...) callback param '${paramName}' at line ${i2 + 1}`,
25401
+ severity: "high",
25402
+ line: i2 + 1,
25403
+ confidence: 0.95,
25404
+ variable: paramName
25405
+ });
25406
+ }
25335
25407
  return sources;
25336
25408
  }
25337
25409
  function findPythonAssignmentSources(sourceCode, language) {
@@ -25664,6 +25736,16 @@ function buildJavaScriptTaintedVars(sourceCode, language) {
25664
25736
  const tainted = new Map;
25665
25737
  const lines = sourceCode.split(`
25666
25738
  `);
25739
+ const CB_EVENT_RE = /\.on\s*\(\s*['"](?:message|text|binary)['"]\s*,\s*(?:async\s+)?(?:function\s*\*?\s*(?:\w+\s*)?\(\s*(\w+)|\(\s*(\w+)\s*(?:[,):]|$)|(\w+)\s*=>)/;
25740
+ for (let i2 = 0;i2 < lines.length; i2++) {
25741
+ const m = lines[i2].match(CB_EVENT_RE);
25742
+ if (!m)
25743
+ continue;
25744
+ const paramName = m[1] ?? m[2] ?? m[3];
25745
+ if (!paramName || paramName === "err" || paramName === "error")
25746
+ continue;
25747
+ tainted.set(paramName, i2 + 1);
25748
+ }
25667
25749
  for (let i2 = 0;i2 < lines.length; i2++) {
25668
25750
  const line = lines[i2];
25669
25751
  const trimmed = line.trimStart();
@@ -25870,6 +25952,90 @@ function findBashTaintSources(sourceCode, dfg) {
25870
25952
  });
25871
25953
  }
25872
25954
  }
25955
+ const readMatch = /^read\s*\(/.test(trimmed) ? null : trimmed.match(/^read\b([^#(]*)$/);
25956
+ if (readMatch) {
25957
+ const argStr = readMatch[1].trim();
25958
+ const noRedirect = argStr.replace(/\s*<[^<].*$/, "").trim();
25959
+ const tokens = noRedirect.split(/\s+/);
25960
+ const varNames = [];
25961
+ for (let ti = 0;ti < tokens.length; ti++) {
25962
+ const tok = tokens[ti];
25963
+ if (!tok)
25964
+ continue;
25965
+ if (tok.startsWith("-")) {
25966
+ if (/^-[antpidu]$|^-N$/.test(tok))
25967
+ ti++;
25968
+ continue;
25969
+ }
25970
+ if (/^[A-Za-z_][\w]*$/.test(tok))
25971
+ varNames.push(tok);
25972
+ }
25973
+ if (varNames.length === 0)
25974
+ varNames.push("REPLY");
25975
+ for (const v of varNames) {
25976
+ const already = sources.some((s) => s.line === lineNumber && s.variable === v);
25977
+ if (already)
25978
+ continue;
25979
+ sources.push({
25980
+ type: "io_input",
25981
+ location: `read → $${v} (stdin)`,
25982
+ severity: "high",
25983
+ line: lineNumber,
25984
+ confidence: 0.9,
25985
+ variable: v
25986
+ });
25987
+ }
25988
+ }
25989
+ const mapfileMatch = /^(?:mapfile|readarray)\s*\(/.test(trimmed) ? null : trimmed.match(/^(?:mapfile|readarray)\b([^#(]*)$/);
25990
+ if (mapfileMatch) {
25991
+ const argStr = mapfileMatch[1].trim();
25992
+ const tokens = argStr.split(/\s+/);
25993
+ const varNames = [];
25994
+ for (let ti = 0;ti < tokens.length; ti++) {
25995
+ const tok = tokens[ti];
25996
+ if (!tok)
25997
+ continue;
25998
+ if (tok.startsWith("-")) {
25999
+ if (/^-[cCnOsud]$/.test(tok))
26000
+ ti++;
26001
+ continue;
26002
+ }
26003
+ if (/^[A-Za-z_][\w]*$/.test(tok))
26004
+ varNames.push(tok);
26005
+ }
26006
+ if (varNames.length === 0)
26007
+ varNames.push("MAPFILE");
26008
+ for (const v of varNames) {
26009
+ const already = sources.some((s) => s.line === lineNumber && s.variable === v);
26010
+ if (already)
26011
+ continue;
26012
+ sources.push({
26013
+ type: "io_input",
26014
+ location: `mapfile → $${v} (stdin array)`,
26015
+ severity: "high",
26016
+ line: lineNumber,
26017
+ confidence: 0.9,
26018
+ variable: v
26019
+ });
26020
+ }
26021
+ }
26022
+ const getoptsMatch = trimmed.match(/\bgetopts\s+["'][^"']+["']\s+(\w+)/);
26023
+ if (getoptsMatch) {
26024
+ const flagVar = getoptsMatch[1];
26025
+ for (const v of [flagVar, "OPTARG"]) {
26026
+ const already = sources.some((s) => s.line === lineNumber && s.variable === v);
26027
+ if (already)
26028
+ continue;
26029
+ sources.push({
26030
+ type: "io_input",
26031
+ location: `getopts → $${v} (CLI arg)`,
26032
+ severity: "high",
26033
+ line: lineNumber,
26034
+ confidence: 0.9,
26035
+ variable: v
26036
+ });
26037
+ }
26038
+ }
25873
26039
  const envRe = /\$([A-Z][A-Z0-9_]{2,})|\$\{([A-Z][A-Z0-9_]{2,})\}/g;
25874
26040
  let em;
25875
26041
  while ((em = envRe.exec(line)) !== null) {
@@ -45650,7 +45816,7 @@ var colors = {
45650
45816
  };
45651
45817
 
45652
45818
  // src/version.ts
45653
- var version = "3.182.0";
45819
+ var version = "3.185.0";
45654
45820
 
45655
45821
  // src/formatters.ts
45656
45822
  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.182.0",
3
+ "version": "3.185.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.182.0"
69
+ "circle-ir": "^3.185.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",