cognium-dev 3.210.0 → 3.213.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 +125 -73
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -11840,8 +11840,6 @@ var DEFAULT_SINKS = [
11840
11840
  { method: "setVariable", class: "Context", type: "xss", cwe: "CWE-79", severity: "medium", arg_positions: [1] },
11841
11841
  { method: "clean", class: "AntiSamy", type: "xss", cwe: "CWE-79", severity: "medium", arg_positions: [0] },
11842
11842
  { method: "getValidSafeHTML", class: "ESAPI", type: "xss", cwe: "CWE-79", severity: "medium", arg_positions: [0] },
11843
- { method: "getAttribute", class: "HttpServletRequest", type: "xss", cwe: "CWE-79", severity: "medium", arg_positions: [] },
11844
- { method: "getAttribute", class: "HttpSession", type: "xss", cwe: "CWE-79", severity: "medium", arg_positions: [] },
11845
11843
  { method: "spawn", class: "Command", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
11846
11844
  { method: "output", class: "Command", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
11847
11845
  { method: "status", class: "Command", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
@@ -14479,6 +14477,73 @@ function isNonExecutablePython(trimmed) {
14479
14477
  return false;
14480
14478
  }
14481
14479
 
14480
+ // ../circle-ir/dist/analysis/sanitizer-index.js
14481
+ var SANITIZER_SET_CACHE = new WeakMap;
14482
+ function getSanitizesSet(san) {
14483
+ let s = SANITIZER_SET_CACHE.get(san);
14484
+ if (!s) {
14485
+ s = new Set(san.sanitizes);
14486
+ SANITIZER_SET_CACHE.set(san, s);
14487
+ }
14488
+ return s;
14489
+ }
14490
+ function sanitizerCoversSink(san, sinkType) {
14491
+ return getSanitizesSet(san).has(sinkType);
14492
+ }
14493
+
14494
+ // ../circle-ir/dist/analysis/dfg-walk.js
14495
+ var walkBackwardDefsMemo = new WeakMap;
14496
+ function walkBackwardDefs(startDefId, chainsByToDef, defById, options = {}) {
14497
+ const maxHops = options.maxHops ?? 32;
14498
+ let perFile = walkBackwardDefsMemo.get(chainsByToDef);
14499
+ if (perFile !== undefined) {
14500
+ const key = `${startDefId}|${maxHops}`;
14501
+ const hit = perFile.get(key);
14502
+ if (hit !== undefined)
14503
+ return hit;
14504
+ }
14505
+ const visited = new Set;
14506
+ const lines = new Set;
14507
+ let hopCapReached = false;
14508
+ const startDef = defById.get(startDefId);
14509
+ if (!startDef) {
14510
+ return { visited, lines, hopCapReached: false };
14511
+ }
14512
+ visited.add(startDefId);
14513
+ lines.add(startDef.line);
14514
+ const queue = [startDefId];
14515
+ let hops = 0;
14516
+ while (queue.length > 0) {
14517
+ if (hops >= maxHops) {
14518
+ hopCapReached = true;
14519
+ break;
14520
+ }
14521
+ hops++;
14522
+ const currentId = queue.shift();
14523
+ const incoming = chainsByToDef.get(currentId);
14524
+ if (!incoming)
14525
+ continue;
14526
+ for (const chain of incoming) {
14527
+ const fromId = chain.from_def;
14528
+ if (visited.has(fromId))
14529
+ continue;
14530
+ visited.add(fromId);
14531
+ const fromDef = defById.get(fromId);
14532
+ if (fromDef) {
14533
+ lines.add(fromDef.line);
14534
+ }
14535
+ queue.push(fromId);
14536
+ }
14537
+ }
14538
+ const result = { visited, lines, hopCapReached };
14539
+ if (perFile === undefined) {
14540
+ perFile = new Map;
14541
+ walkBackwardDefsMemo.set(chainsByToDef, perFile);
14542
+ }
14543
+ perFile.set(`${startDefId}|${maxHops}`, result);
14544
+ return result;
14545
+ }
14546
+
14482
14547
  // ../circle-ir/dist/analysis/findings.js
14483
14548
  function canSourceReachSink(sourceType, sinkType) {
14484
14549
  const sourceToSinkMapping = {
@@ -16765,73 +16830,6 @@ class AnalysisPipeline {
16765
16830
  return { results, findings };
16766
16831
  }
16767
16832
  }
16768
- // ../circle-ir/dist/analysis/dfg-walk.js
16769
- var walkBackwardDefsMemo = new WeakMap;
16770
- function walkBackwardDefs(startDefId, chainsByToDef, defById, options = {}) {
16771
- const maxHops = options.maxHops ?? 32;
16772
- let perFile = walkBackwardDefsMemo.get(chainsByToDef);
16773
- if (perFile !== undefined) {
16774
- const key = `${startDefId}|${maxHops}`;
16775
- const hit = perFile.get(key);
16776
- if (hit !== undefined)
16777
- return hit;
16778
- }
16779
- const visited = new Set;
16780
- const lines = new Set;
16781
- let hopCapReached = false;
16782
- const startDef = defById.get(startDefId);
16783
- if (!startDef) {
16784
- return { visited, lines, hopCapReached: false };
16785
- }
16786
- visited.add(startDefId);
16787
- lines.add(startDef.line);
16788
- const queue = [startDefId];
16789
- let hops = 0;
16790
- while (queue.length > 0) {
16791
- if (hops >= maxHops) {
16792
- hopCapReached = true;
16793
- break;
16794
- }
16795
- hops++;
16796
- const currentId = queue.shift();
16797
- const incoming = chainsByToDef.get(currentId);
16798
- if (!incoming)
16799
- continue;
16800
- for (const chain of incoming) {
16801
- const fromId = chain.from_def;
16802
- if (visited.has(fromId))
16803
- continue;
16804
- visited.add(fromId);
16805
- const fromDef = defById.get(fromId);
16806
- if (fromDef) {
16807
- lines.add(fromDef.line);
16808
- }
16809
- queue.push(fromId);
16810
- }
16811
- }
16812
- const result = { visited, lines, hopCapReached };
16813
- if (perFile === undefined) {
16814
- perFile = new Map;
16815
- walkBackwardDefsMemo.set(chainsByToDef, perFile);
16816
- }
16817
- perFile.set(`${startDefId}|${maxHops}`, result);
16818
- return result;
16819
- }
16820
-
16821
- // ../circle-ir/dist/analysis/sanitizer-index.js
16822
- var SANITIZER_SET_CACHE = new WeakMap;
16823
- function getSanitizesSet(san) {
16824
- let s = SANITIZER_SET_CACHE.get(san);
16825
- if (!s) {
16826
- s = new Set(san.sanitizes);
16827
- SANITIZER_SET_CACHE.set(san, s);
16828
- }
16829
- return s;
16830
- }
16831
- function sanitizerCoversSink(san, sinkType) {
16832
- return getSanitizesSet(san).has(sinkType);
16833
- }
16834
-
16835
16833
  // ../circle-ir/dist/analysis/taint-propagation.js
16836
16834
  function buildSanitizersByLine(sanitizers) {
16837
16835
  const out2 = new Map;
@@ -24784,6 +24782,7 @@ class LanguageSourcesPass {
24784
24782
  additionalSanitizers.push(...findJavaSafeJsonParseSanitizers(code));
24785
24783
  additionalSanitizers.push(...findJavaPathNormalizeStartsWithGuardSanitizers(code));
24786
24784
  additionalSanitizers.push(...findJavaPathGetFileNameSanitizers(code));
24785
+ additionalSanitizers.push(...findJavaCanonicalPathStartsWithGuardSanitizers(code));
24787
24786
  additionalSanitizers.push(...findJavaInlineCrlfStripLogSanitizers(code));
24788
24787
  additionalSanitizers.push(...findJavaArgvFormExecSanitizers(code));
24789
24788
  for (const finding of findJavaPatternFindings(code, graph.ir.meta.file)) {
@@ -27640,6 +27639,58 @@ function findJavaPathNormalizeStartsWithGuardSanitizers(code) {
27640
27639
  }
27641
27640
  return sanitizers;
27642
27641
  }
27642
+ function findJavaCanonicalPathStartsWithGuardSanitizers(code) {
27643
+ const sanitizers = [];
27644
+ const lines = code.split(`
27645
+ `);
27646
+ const guardRe = /\bif\s*\(\s*!\s*([A-Za-z_]\w*)\s*\.\s*getCanonicalPath\s*\(\s*\)\s*\.\s*startsWith\s*\(/;
27647
+ const terminatorRe = /\b(throw|return)\b/;
27648
+ const assignRe = /^\s*(?:[A-Za-z_][\w.<>[\]]*\s+)?([A-Za-z_]\w*)\s*=(?!=)\s*(.*)$/;
27649
+ for (let i2 = 0;i2 < lines.length; i2++) {
27650
+ const m = guardRe.exec(lines[i2]);
27651
+ if (!m)
27652
+ continue;
27653
+ let hasTerminator = terminatorRe.test(lines[i2]);
27654
+ if (!hasTerminator) {
27655
+ for (let j = i2 + 1;j < Math.min(lines.length, i2 + 6); j++) {
27656
+ if (terminatorRe.test(lines[j])) {
27657
+ hasTerminator = true;
27658
+ break;
27659
+ }
27660
+ if (lines[j].includes("}"))
27661
+ break;
27662
+ }
27663
+ }
27664
+ if (!hasTerminator)
27665
+ continue;
27666
+ const guarded = new Set([m[1]]);
27667
+ const mentions = (t) => {
27668
+ for (const n of guarded)
27669
+ if (new RegExp(`\\b${n}\\b`).test(t))
27670
+ return true;
27671
+ return false;
27672
+ };
27673
+ for (let l = 0;l < lines.length; l++) {
27674
+ const lt = lines[l];
27675
+ const a = assignRe.exec(lt);
27676
+ if (a) {
27677
+ if (mentions(a[2]))
27678
+ guarded.add(a[1]);
27679
+ else if (a[1] !== m[1])
27680
+ guarded.delete(a[1]);
27681
+ }
27682
+ if (mentions(lt)) {
27683
+ sanitizers.push({
27684
+ type: "java_canonical_startswith_guard",
27685
+ method: "getCanonicalPath",
27686
+ line: l + 1,
27687
+ sanitizes: ["path_traversal", "external_taint_escape"]
27688
+ });
27689
+ }
27690
+ }
27691
+ }
27692
+ return sanitizers;
27693
+ }
27643
27694
  function findJavaPathGetFileNameSanitizers(code) {
27644
27695
  const sanitizers = [];
27645
27696
  const lines = code.split(`
@@ -27647,15 +27698,16 @@ function findJavaPathGetFileNameSanitizers(code) {
27647
27698
  const assignmentRe = /^\s*(?:(?:final\s+)?[A-Za-z_][\w.<>?,\s\[\]]*?\s+)?([A-Za-z_]\w*)\s*=\s*(.+?);\s*$/;
27648
27699
  const rhsHasGetFileNameRe = /\.\s*getFileName\s*\(\s*\)/;
27649
27700
  const rhsHasPathsChainRe = /\b(?:Paths\s*\.\s*get|Path\s*\.\s*of)\s*\(/;
27701
+ const rhsNewFileGetNameRe = /\bnew\s+File\s*\([\s\S]*\)\s*\.\s*getName\s*\(\s*\)/;
27650
27702
  const candidates = [];
27651
27703
  for (let i2 = 0;i2 < lines.length; i2++) {
27652
27704
  const m = assignmentRe.exec(lines[i2]);
27653
27705
  if (!m)
27654
27706
  continue;
27655
27707
  const rhs = m[2];
27656
- if (!rhsHasGetFileNameRe.test(rhs))
27657
- continue;
27658
- if (!rhsHasPathsChainRe.test(rhs))
27708
+ const isNioGetFileName = rhsHasGetFileNameRe.test(rhs) && rhsHasPathsChainRe.test(rhs);
27709
+ const isNewFileGetName = rhsNewFileGetNameRe.test(rhs);
27710
+ if (!isNioGetFileName && !isNewFileGetName)
27659
27711
  continue;
27660
27712
  candidates.push({ line: i2 + 1, boundVar: m[1] });
27661
27713
  }
@@ -47084,7 +47136,7 @@ var colors = {
47084
47136
  };
47085
47137
 
47086
47138
  // src/version.ts
47087
- var version = "3.210.0";
47139
+ var version = "3.213.0";
47088
47140
 
47089
47141
  // src/formatters.ts
47090
47142
  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.210.0",
3
+ "version": "3.213.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.210.0"
69
+ "circle-ir": "^3.213.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",