cognium-dev 4.14.0 → 4.14.1

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 +85 -28
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -9641,6 +9641,38 @@ function extractFieldDefs(body2, startId) {
9641
9641
  function extractJSParameterDefs(params, startId) {
9642
9642
  const defs = [];
9643
9643
  let id = startId;
9644
+ const addPatternDefs = (patternNode, line) => {
9645
+ if (patternNode.type === "identifier" || patternNode.type === "shorthand_property_identifier_pattern") {
9646
+ defs.push({
9647
+ id: id++,
9648
+ variable: getNodeText(patternNode),
9649
+ line,
9650
+ kind: "param"
9651
+ });
9652
+ return;
9653
+ }
9654
+ if (patternNode.type === "rest_pattern" || patternNode.type === "rest_element") {
9655
+ const nameNode = patternNode.namedChildCount > 0 ? patternNode.namedChild(0) : null;
9656
+ if (!nameNode)
9657
+ return;
9658
+ addPatternDefs(nameNode, line);
9659
+ return;
9660
+ }
9661
+ if (patternNode.type === "assignment_pattern") {
9662
+ const leftNode = patternNode.childForFieldName("left");
9663
+ if (leftNode)
9664
+ addPatternDefs(leftNode, line);
9665
+ return;
9666
+ }
9667
+ if (patternNode.type === "object_pattern" || patternNode.type === "array_pattern") {
9668
+ const destructDefs = extractDestructuringDefs(patternNode, id);
9669
+ for (const def of destructDefs) {
9670
+ def.kind = "param";
9671
+ defs.push(def);
9672
+ id++;
9673
+ }
9674
+ }
9675
+ };
9644
9676
  for (let i2 = 0;i2 < params.childCount; i2++) {
9645
9677
  const param = params.child(i2);
9646
9678
  if (!param)
@@ -9690,14 +9722,8 @@ function extractJSParameterDefs(params, startId) {
9690
9722
  }
9691
9723
  } else if (param.type === "required_parameter" || param.type === "optional_parameter") {
9692
9724
  const patternNode = param.childForFieldName("pattern");
9693
- if (patternNode && patternNode.type === "identifier") {
9694
- defs.push({
9695
- id: id++,
9696
- variable: getNodeText(patternNode),
9697
- line: param.startPosition.row + 1,
9698
- kind: "param"
9699
- });
9700
- }
9725
+ if (patternNode)
9726
+ addPatternDefs(patternNode, param.startPosition.row + 1);
9701
9727
  }
9702
9728
  }
9703
9729
  return defs;
@@ -13808,7 +13834,8 @@ function findSources(calls, types, patterns, sourceLines, language) {
13808
13834
  continue;
13809
13835
  for (const param of method.parameters) {
13810
13836
  const hasCSharpBindingAttr = language === "csharp" && param.annotations.some((a) => CSHARP_BINDING_ATTRS.has(a));
13811
- const isTaintable = hasCSharpBindingAttr ? true : param.type ? isInterproceduralTaintableType(param.type, language) : true;
13837
+ const isDestructureBinding = param.name.startsWith("{") || param.name.startsWith("[");
13838
+ const isTaintable = hasCSharpBindingAttr ? true : isDestructureBinding ? true : param.type ? isInterproceduralTaintableType(param.type, language) : true;
13812
13839
  if (isTaintable) {
13813
13840
  const paramLine = param.line ?? method.start_line;
13814
13841
  sources.push({
@@ -18264,6 +18291,9 @@ function buildSanitizersByLine(sanitizers) {
18264
18291
  }
18265
18292
  return out2;
18266
18293
  }
18294
+ function concatOutsideStrings(expression) {
18295
+ return expression.replace(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/g, " ").includes("+");
18296
+ }
18267
18297
  function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanitizers, sanitizersArg) {
18268
18298
  let graph;
18269
18299
  let sources;
@@ -18295,6 +18325,7 @@ function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanit
18295
18325
  }
18296
18326
  const taintedVars = [];
18297
18327
  const flows = [];
18328
+ const javaConcat = graph.ir.meta.language === "java";
18298
18329
  const reachableSinks = new Map;
18299
18330
  const defsByLine = graph.defsByLine;
18300
18331
  const usesByLine = graph.usesByLine;
@@ -18327,12 +18358,14 @@ function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanit
18327
18358
  continue;
18328
18359
  }
18329
18360
  }
18330
- const candidateUses = arg.variable ? usesAtSink.filter((u) => u.variable === arg.variable) : usesAtSink;
18361
+ const expr = typeof arg.expression === "string" ? arg.expression : "";
18362
+ const compoundConcat = javaConcat && !!arg.variable && expr !== arg.variable && concatOutsideStrings(expr);
18363
+ const candidateUses = arg.variable && !compoundConcat ? usesAtSink.filter((u) => u.variable === arg.variable) : usesAtSink;
18331
18364
  {
18332
18365
  for (const use of candidateUses) {
18333
18366
  if (use.def_id !== null) {
18334
18367
  if (allTaintedDefIds.has(use.def_id)) {
18335
- if (!arg.variable) {
18368
+ if (!arg.variable || compoundConcat) {
18336
18369
  if (typeof arg.expression !== "string" || arg.expression.length === 0)
18337
18370
  continue;
18338
18371
  const re = new RegExp(`(?:^|[^A-Za-z0-9_$])${use.variable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:[^A-Za-z0-9_$]|$)`);
@@ -36477,6 +36510,22 @@ function evaluateSimpleExpression(expr, symbols) {
36477
36510
  return String(Math.floor(result));
36478
36511
  return expr;
36479
36512
  }
36513
+ var ARGUMENT_IDENT_SKIP = new Set(["new", "true", "false", "null", "this", "super"]);
36514
+ function isStringConcat(expression) {
36515
+ return expression.replace(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/g, " ").includes("+");
36516
+ }
36517
+ function argumentIdentifiers(expression) {
36518
+ const stripped = expression.replace(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/g, " ");
36519
+ const found = stripped.match(/[A-Za-z_$][A-Za-z0-9_$]*/g) ?? [];
36520
+ const out2 = [];
36521
+ for (const id of found) {
36522
+ if (ARGUMENT_IDENT_SKIP.has(id))
36523
+ continue;
36524
+ if (!out2.includes(id))
36525
+ out2.push(id);
36526
+ }
36527
+ return out2;
36528
+ }
36480
36529
  function isStringLiteralExpression(expr) {
36481
36530
  const trimmed = expr.trim();
36482
36531
  if (trimmed.length < 2)
@@ -36555,22 +36604,30 @@ function filterCleanVariableSinks(sinks, calls, taintedVars, symbols, dfg, sanit
36555
36604
  if (language === "bash" && arg.expression === call.method_name && !arg.variable && arg.literal == null)
36556
36605
  continue;
36557
36606
  if (arg.variable && !arg.expression?.includes("[")) {
36558
- const varName = arg.variable;
36559
- const scopedName = methodName ? `${methodName}:${varName}` : varName;
36560
- if (fieldNames.has(varName) && !isInSynchronizedBlock) {
36561
- allArgsAreClean = false;
36562
- continue;
36607
+ const expr = arg.expression ?? "";
36608
+ const concatNames = language === "java" && isStringConcat(expr) ? argumentIdentifiers(expr) : [];
36609
+ const names = concatNames.length > 0 ? concatNames : [arg.variable];
36610
+ let argClean = true;
36611
+ for (const varName of names) {
36612
+ const scopedName = methodName ? `${methodName}:${varName}` : varName;
36613
+ if (fieldNames.has(varName) && !isInSynchronizedBlock) {
36614
+ argClean = false;
36615
+ break;
36616
+ }
36617
+ if (sanitizedVars?.has(scopedName) || sanitizedVars?.has(varName))
36618
+ continue;
36619
+ if (taintedVars.has(scopedName) || taintedVars.has(varName)) {
36620
+ argClean = false;
36621
+ break;
36622
+ }
36623
+ const symbolValue = symbols.get(scopedName) ?? symbols.get(varName);
36624
+ if (symbolValue && symbolValue.type !== "unknown")
36625
+ continue;
36626
+ argClean = false;
36627
+ break;
36563
36628
  }
36564
- if (sanitizedVars?.has(scopedName) || sanitizedVars?.has(varName))
36565
- continue;
36566
- if (taintedVars.has(scopedName) || taintedVars.has(varName)) {
36629
+ if (!argClean)
36567
36630
  allArgsAreClean = false;
36568
- continue;
36569
- }
36570
- const symbolValue = symbols.get(scopedName) ?? symbols.get(varName);
36571
- if (symbolValue && symbolValue.type !== "unknown")
36572
- continue;
36573
- allArgsAreClean = false;
36574
36631
  } else {
36575
36632
  if (arg.literal != null)
36576
36633
  continue;
@@ -52098,7 +52155,7 @@ var colors = {
52098
52155
  };
52099
52156
 
52100
52157
  // src/version.ts
52101
- var version = "4.14.0";
52158
+ var version = "4.14.1";
52102
52159
 
52103
52160
  // src/formatters.ts
52104
52161
  var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
@@ -52665,8 +52722,8 @@ function generateSarifResults(results, crossFileData) {
52665
52722
 
52666
52723
  // src/build-info.ts
52667
52724
  var buildInfo = {
52668
- gitSha: "c44e104",
52669
- builtAt: "2026-10-11T06:19:30.837Z"
52725
+ gitSha: "c8c74e9",
52726
+ builtAt: "2026-10-11T07:15:24.915Z"
52670
52727
  };
52671
52728
 
52672
52729
  // src/utils/args.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "4.14.0",
3
+ "version": "4.14.1",
4
4
  "description": "Static Application Security Testing CLI for detecting security vulnerabilities via taint tracking",
5
5
  "bin": {
6
6
  "cognium-dev": "dist/cli.js"
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "dependencies": {
67
67
  "@cognium/project-profile-detect": "1.1.2",
68
- "circle-ir": "4.14.0"
68
+ "circle-ir": "4.14.1"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/node": "^26.6.4",