cognium-dev 3.35.0 → 3.37.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 +109 -1
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -19451,6 +19451,15 @@ function buildPythonTaintedVars(sourceCode) {
19451
19451
  containerTainted.set(`${obj}['${section}']['${key}']`, i2 + 1);
19452
19452
  continue;
19453
19453
  }
19454
+ const containerAppendMatch = line.match(/^\s*(\w+)\.(append|extend|insert|add|push|put|appendleft)\s*\(\s*(.+?)\s*\)\s*$/);
19455
+ if (containerAppendMatch) {
19456
+ const [, receiver, , argExpr] = containerAppendMatch;
19457
+ const argIsTainted = [...tainted.keys()].some((v) => new RegExp(`\\b${v}\\b`).test(argExpr));
19458
+ const argIsDirectSource = PYTHON_TAINTED_PATTERNS2.some((p) => p.pattern.test(argExpr));
19459
+ if (argIsTainted || argIsDirectSource)
19460
+ tainted.set(receiver, tainted.get(receiver) ?? i2 + 1);
19461
+ continue;
19462
+ }
19454
19463
  const augAssign = line.match(/^\s*(\w+)\s*\+=\s*(.+)$/);
19455
19464
  if (augAssign) {
19456
19465
  const [, augLhs, augRhs] = augAssign;
@@ -20513,6 +20522,28 @@ class TaintPropagationPass {
20513
20522
  flows.push(f);
20514
20523
  }
20515
20524
  }
20525
+ const exprScanFlows = detectExpressionScanFlows(calls, sources, sinks, constProp.unreachableLines, ctx.code, ctx.language) ?? [];
20526
+ for (const f of exprScanFlows) {
20527
+ if (flows.some((x) => x.source_line === f.source_line && x.sink_line === f.sink_line && x.sink_type === f.sink_type))
20528
+ continue;
20529
+ const flowForCheck = {
20530
+ source: { line: f.source_line },
20531
+ sink: { line: f.sink_line },
20532
+ path: f.path.map((p) => ({ variable: p.variable, line: p.line }))
20533
+ };
20534
+ if (isCorrelatedPredicateFP(constProp, flowForCheck))
20535
+ continue;
20536
+ let isFP = false;
20537
+ for (const step of f.path) {
20538
+ if (isFalsePositive(constProp, step.line, step.variable).isFalsePositive) {
20539
+ isFP = true;
20540
+ break;
20541
+ }
20542
+ }
20543
+ if (isFP)
20544
+ continue;
20545
+ flows.push(f);
20546
+ }
20516
20547
  return { flows };
20517
20548
  }
20518
20549
  }
@@ -20709,6 +20740,83 @@ function detectParameterSinkFlows(types, calls, sources, sinks, unreachableLines
20709
20740
  }
20710
20741
  return flows;
20711
20742
  }
20743
+ function detectExpressionScanFlows(calls, sources, sinks, unreachableLines, code, language) {
20744
+ const flows = [];
20745
+ const sourcesWithVar = sources.filter((s) => typeof s.variable === "string" && s.variable.length > 0);
20746
+ if (sourcesWithVar.length === 0)
20747
+ return flows;
20748
+ if (language === "python" && typeof code === "string") {
20749
+ const derived = buildPythonTaintedVars(code);
20750
+ if (derived.size > 0) {
20751
+ let anchor = sourcesWithVar[0];
20752
+ for (const s of sourcesWithVar) {
20753
+ if (s.line < anchor.line)
20754
+ anchor = s;
20755
+ }
20756
+ const existingVars = new Set(sourcesWithVar.map((s) => s.variable));
20757
+ for (const [varName] of derived) {
20758
+ if (!varName || existingVars.has(varName))
20759
+ continue;
20760
+ sourcesWithVar.push({
20761
+ ...anchor,
20762
+ variable: varName
20763
+ });
20764
+ existingVars.add(varName);
20765
+ }
20766
+ }
20767
+ }
20768
+ const reCache = new Map;
20769
+ for (const s of sourcesWithVar) {
20770
+ if (reCache.has(s.variable))
20771
+ continue;
20772
+ const escaped = s.variable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
20773
+ reCache.set(s.variable, new RegExp(`\\b${escaped}\\b`));
20774
+ }
20775
+ const callsByLine = new Map;
20776
+ for (const call of calls) {
20777
+ const existing = callsByLine.get(call.location.line) ?? [];
20778
+ existing.push(call);
20779
+ callsByLine.set(call.location.line, existing);
20780
+ }
20781
+ for (const sink of sinks) {
20782
+ if (unreachableLines.has(sink.line))
20783
+ continue;
20784
+ const callsAtSink = callsByLine.get(sink.line) ?? [];
20785
+ for (const call of callsAtSink) {
20786
+ for (const arg of call.arguments) {
20787
+ if (sink.argPositions && sink.argPositions.length > 0 && !sink.argPositions.includes(arg.position)) {
20788
+ continue;
20789
+ }
20790
+ const expr = arg.expression;
20791
+ if (!expr)
20792
+ continue;
20793
+ for (const source of sourcesWithVar) {
20794
+ if (source.line >= sink.line)
20795
+ continue;
20796
+ const re = reCache.get(source.variable);
20797
+ if (!re || !re.test(expr))
20798
+ continue;
20799
+ if (flows.some((f) => f.source_line === source.line && f.sink_line === sink.line && f.sink_type === sink.type))
20800
+ continue;
20801
+ flows.push({
20802
+ source_line: source.line,
20803
+ sink_line: sink.line,
20804
+ source_type: source.type,
20805
+ sink_type: sink.type,
20806
+ path: [
20807
+ { variable: source.variable, line: source.line, type: "source" },
20808
+ { variable: source.variable, line: sink.line, type: "sink" }
20809
+ ],
20810
+ confidence: source.confidence * sink.confidence * 0.7,
20811
+ sanitized: false
20812
+ });
20813
+ break;
20814
+ }
20815
+ }
20816
+ }
20817
+ }
20818
+ return flows;
20819
+ }
20712
20820
 
20713
20821
  // ../circle-ir/dist/analysis/interprocedural.js
20714
20822
  function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourcesOrSanitizers, sinksOrOptions, sanitizersArg, optionsArg = {}) {
@@ -26875,7 +26983,7 @@ var colors = {
26875
26983
  };
26876
26984
 
26877
26985
  // src/version.ts
26878
- var version = "3.35.0";
26986
+ var version = "3.37.0";
26879
26987
 
26880
26988
  // src/formatters.ts
26881
26989
  var SINK_SEVERITY = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "3.35.0",
3
+ "version": "3.37.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.35.0"
68
+ "circle-ir": "^3.37.0"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/node": "^25.5.0",