cognium-dev 3.159.0 → 3.160.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 +55 -6
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -12982,7 +12982,10 @@ function matchesSinkPattern(call, pattern, typeHierarchy, language) {
12982
12982
  return true;
12983
12983
  }
12984
12984
  const subtypeArgArityOk = !pattern.arg_positions || pattern.arg_positions.length === 0 || pattern.arg_positions.every((pos) => pos < (call.arguments?.length ?? 0));
12985
- if (call.receiver_type && call.receiver_type === pattern.class) {} else if (call.receiver_type && typeHierarchy && subtypeArgArityOk && typeHierarchy.isSubtypeOf(call.receiver_type, pattern.class)) {} else if (call.receiver_type_fqn && call.receiver_type_fqn.endsWith("." + pattern.class)) {} else if (call.receiver_type_fqn && typeHierarchy && subtypeArgArityOk && typeHierarchy.isSubtypeOf(call.receiver_type_fqn, pattern.class)) {} else if (call.receiver && !receiverMightBeClass(call.receiver, pattern.class)) {
12985
+ if (call.receiver_type && call.receiver_type === pattern.class) {} else if (call.receiver_type && typeHierarchy && subtypeArgArityOk && typeHierarchy.isSubtypeOf(call.receiver_type, pattern.class)) {} else if (call.receiver_type_fqn && call.receiver_type_fqn.endsWith("." + pattern.class)) {} else if (call.receiver_type_fqn && typeHierarchy && subtypeArgArityOk && typeHierarchy.isSubtypeOf(call.receiver_type_fqn, pattern.class)) {} else if (!call.receiver_type && !call.receiver_type_fqn && call.receiver && typeHierarchy && subtypeArgArityOk && (() => {
12986
+ const factoryReturn = typeHierarchy.resolveFactoryReturnType(call.receiver);
12987
+ return factoryReturn !== null && typeHierarchy.isSubtypeOf(factoryReturn, pattern.class);
12988
+ })()) {} else if (call.receiver && !receiverMightBeClass(call.receiver, pattern.class)) {
12986
12989
  if (typeHierarchy && typeHierarchy.couldBeType(call.receiver, pattern.class)) {
12987
12990
  return true;
12988
12991
  }
@@ -13915,6 +13918,7 @@ class TypeHierarchyResolver {
13915
13918
  implementations = new Map;
13916
13919
  _subtypeCache = new Map;
13917
13920
  _implCache = new Map;
13921
+ factoryReturnTypes = new Map;
13918
13922
  addFromIR(ir, filePath) {
13919
13923
  for (const type of ir.types) {
13920
13924
  this.addType(type, filePath, ir.meta.package || null);
@@ -14120,11 +14124,22 @@ class TypeHierarchyResolver {
14120
14124
  getAllTypes() {
14121
14125
  return Array.from(this.types.values());
14122
14126
  }
14127
+ registerFactoryReturnType(factoryClass, method, returnFqn) {
14128
+ this.factoryReturnTypes.set(`${factoryClass}.${method}`, returnFqn);
14129
+ }
14130
+ resolveFactoryReturnType(receiver) {
14131
+ const m = receiver.match(/(?:^|\.)([A-Z]\w*)\.(\w+)\(\)$/);
14132
+ if (!m)
14133
+ return null;
14134
+ const key = `${m[1]}.${m[2]}`;
14135
+ return this.factoryReturnTypes.get(key) ?? null;
14136
+ }
14123
14137
  clear() {
14124
14138
  this.types.clear();
14125
14139
  this.nameToFqn.clear();
14126
14140
  this.subtypes.clear();
14127
14141
  this.implementations.clear();
14142
+ this.factoryReturnTypes.clear();
14128
14143
  }
14129
14144
  resolveTypeName(name2, currentPackage) {
14130
14145
  if (name2.includes("."))
@@ -14463,6 +14478,9 @@ function registerCommonLibraries(resolver) {
14463
14478
  for (const type of [...apacheHttpClient4x, ...apacheHttpClient5x]) {
14464
14479
  resolver.addType(type, "common-libraries", type.package);
14465
14480
  }
14481
+ resolver.registerFactoryReturnType("HttpClients", "createDefault", "org.apache.http.impl.client.CloseableHttpClient");
14482
+ resolver.registerFactoryReturnType("HttpClients", "createSystem", "org.apache.http.impl.client.CloseableHttpClient");
14483
+ resolver.registerFactoryReturnType("HttpClients", "createMinimal", "org.apache.http.impl.client.MinimalHttpClient");
14466
14484
  }
14467
14485
  // ../circle-ir/dist/resolution/symbol-table.js
14468
14486
  class SymbolTable {
@@ -29828,6 +29846,12 @@ function correlateDollarBraceToArgPositions(method, refs) {
29828
29846
  }
29829
29847
  }
29830
29848
  });
29849
+ const declaredNameToIndex = new Map;
29850
+ method.parameters.forEach((param, idx) => {
29851
+ if (param.name && !declaredNameToIndex.has(param.name)) {
29852
+ declaredNameToIndex.set(param.name, idx);
29853
+ }
29854
+ });
29831
29855
  const positions = new Set;
29832
29856
  for (const ref of refs) {
29833
29857
  const namedIdx = paramNameToIndex.get(ref);
@@ -29835,6 +29859,11 @@ function correlateDollarBraceToArgPositions(method, refs) {
29835
29859
  positions.add(namedIdx);
29836
29860
  continue;
29837
29861
  }
29862
+ const declaredIdx = declaredNameToIndex.get(ref);
29863
+ if (declaredIdx !== undefined) {
29864
+ positions.add(declaredIdx);
29865
+ continue;
29866
+ }
29838
29867
  const positionalIdx = parsePositionalRef(ref);
29839
29868
  if (positionalIdx !== null && positionalIdx < method.parameters.length) {
29840
29869
  positions.add(positionalIdx);
@@ -29865,11 +29894,11 @@ class MyBatisAnnotationSqlSinkPass {
29865
29894
  category = "security";
29866
29895
  run(ctx) {
29867
29896
  if (ctx.language !== "java") {
29868
- return { annotatedMethodCount: 0, addedSinkCount: 0 };
29897
+ return { annotatedMethodCount: 0, addedSinkCount: 0, declarationFindingCount: 0 };
29869
29898
  }
29870
29899
  const { types, imports, calls } = ctx.graph.ir;
29871
29900
  if (!fileImportsMyBatis(imports)) {
29872
- return { annotatedMethodCount: 0, addedSinkCount: 0 };
29901
+ return { annotatedMethodCount: 0, addedSinkCount: 0, declarationFindingCount: 0 };
29873
29902
  }
29874
29903
  const mapperMethods = [];
29875
29904
  for (const type of types) {
@@ -29898,6 +29927,7 @@ class MyBatisAnnotationSqlSinkPass {
29898
29927
  interfaceSimpleName: type.name,
29899
29928
  interfaceFqn,
29900
29929
  methodName: method.name,
29930
+ declarationLine: method.start_line,
29901
29931
  taintedArgPositions: positions
29902
29932
  });
29903
29933
  }
@@ -29905,9 +29935,27 @@ class MyBatisAnnotationSqlSinkPass {
29905
29935
  if (mapperMethods.length === 0) {
29906
29936
  return {
29907
29937
  annotatedMethodCount: 0,
29908
- addedSinkCount: 0
29938
+ addedSinkCount: 0,
29939
+ declarationFindingCount: 0
29909
29940
  };
29910
29941
  }
29942
+ const file = ctx.graph.ir.meta.file;
29943
+ let declarationFindingCount = 0;
29944
+ for (const rec of mapperMethods) {
29945
+ ctx.addFinding({
29946
+ id: `${this.name}-${file}-${rec.declarationLine}-${rec.methodName}`,
29947
+ pass: this.name,
29948
+ category: this.category,
29949
+ rule_id: this.name,
29950
+ cwe: "CWE-89",
29951
+ severity: "critical",
29952
+ level: "error",
29953
+ message: `MyBatis Mapper method \`${rec.interfaceSimpleName}.${rec.methodName}\` uses raw ` + `\`\${}\` interpolation in its @Select/@Update/@Insert/@Delete annotation. ` + `Any caller passing dynamic input into arg position(s) ` + `${rec.taintedArgPositions.join(", ")} will execute unbound SQL (CWE-89). ` + `Replace \`\${x}\` with \`#{x}\` to enable JDBC parameter binding.`,
29954
+ file,
29955
+ line: rec.declarationLine
29956
+ });
29957
+ declarationFindingCount++;
29958
+ }
29911
29959
  const sinks = ctx.hasResult("taint-matcher") ? ctx.getResult("taint-matcher").sinks : ctx.graph.ir.taint.sinks;
29912
29960
  let addedSinkCount = 0;
29913
29961
  for (const call of calls) {
@@ -29935,7 +29983,8 @@ class MyBatisAnnotationSqlSinkPass {
29935
29983
  }
29936
29984
  return {
29937
29985
  annotatedMethodCount: mapperMethods.length,
29938
- addedSinkCount
29986
+ addedSinkCount,
29987
+ declarationFindingCount
29939
29988
  };
29940
29989
  }
29941
29990
  }
@@ -43751,7 +43800,7 @@ var colors = {
43751
43800
  };
43752
43801
 
43753
43802
  // src/version.ts
43754
- var version = "3.159.0";
43803
+ var version = "3.160.0";
43755
43804
 
43756
43805
  // src/formatters.ts
43757
43806
  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.159.0",
3
+ "version": "3.160.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.159.0"
69
+ "circle-ir": "^3.160.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",