cognium-dev 3.159.0 → 3.161.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 +98 -8
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -11520,7 +11520,24 @@ var DEFAULT_SINKS = [
11520
11520
  { method: "outerHTML", type: "xss", cwe: "CWE-79", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
11521
11521
  { method: "unserialize", class: "serialize", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
11522
11522
  { method: "unserialize", class: "node-serialize", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
11523
- { method: "unserialize", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] }
11523
+ { method: "unserialize", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
11524
+ { method: "get", class: "httpx", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
11525
+ { method: "post", class: "httpx", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
11526
+ { method: "request", class: "httpx", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [1] },
11527
+ { method: "stream", class: "httpx", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [1] },
11528
+ { method: "delete", class: "httpx", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
11529
+ { method: "put", class: "httpx", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
11530
+ { method: "patch", class: "httpx", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
11531
+ { method: "head", class: "httpx", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
11532
+ { method: "execute", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
11533
+ { method: "fetch", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
11534
+ { method: "fetchrow", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
11535
+ { method: "fetchval", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
11536
+ { method: "fetchrow", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["python"] },
11537
+ { method: "fetchval", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["python"] },
11538
+ { method: "Redirect", class: "http", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [2], languages: ["go"] },
11539
+ { method: "Do", class: "Client", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["go"] },
11540
+ { method: "DoTimeout", class: "Client", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["go"] }
11524
11541
  ];
11525
11542
  var DEFAULT_SANITIZERS = [
11526
11543
  { method: "setString", class: "PreparedStatement", removes: ["sql_injection"] },
@@ -12982,7 +12999,10 @@ function matchesSinkPattern(call, pattern, typeHierarchy, language) {
12982
12999
  return true;
12983
13000
  }
12984
13001
  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)) {
13002
+ 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 && (() => {
13003
+ const factoryReturn = typeHierarchy.resolveFactoryReturnType(call.receiver);
13004
+ return factoryReturn !== null && typeHierarchy.isSubtypeOf(factoryReturn, pattern.class);
13005
+ })()) {} else if (call.receiver && !receiverMightBeClass(call.receiver, pattern.class)) {
12986
13006
  if (typeHierarchy && typeHierarchy.couldBeType(call.receiver, pattern.class)) {
12987
13007
  return true;
12988
13008
  }
@@ -13055,7 +13075,7 @@ function receiverMightBeClass(receiver, className) {
13055
13075
  }
13056
13076
  const lowerReceiver = receiver.toLowerCase();
13057
13077
  const lowerClass = className.toLowerCase();
13058
- if (lowerReceiver.endsWith(lowerClass) || lowerReceiver.endsWith("." + lowerClass)) {
13078
+ if (lowerReceiver === lowerClass || lowerReceiver.endsWith("." + lowerClass)) {
13059
13079
  return true;
13060
13080
  }
13061
13081
  if (receiver.includes(".") && !receiver.endsWith(")")) {
@@ -13915,6 +13935,7 @@ class TypeHierarchyResolver {
13915
13935
  implementations = new Map;
13916
13936
  _subtypeCache = new Map;
13917
13937
  _implCache = new Map;
13938
+ factoryReturnTypes = new Map;
13918
13939
  addFromIR(ir, filePath) {
13919
13940
  for (const type of ir.types) {
13920
13941
  this.addType(type, filePath, ir.meta.package || null);
@@ -14120,11 +14141,22 @@ class TypeHierarchyResolver {
14120
14141
  getAllTypes() {
14121
14142
  return Array.from(this.types.values());
14122
14143
  }
14144
+ registerFactoryReturnType(factoryClass, method, returnFqn) {
14145
+ this.factoryReturnTypes.set(`${factoryClass}.${method}`, returnFqn);
14146
+ }
14147
+ resolveFactoryReturnType(receiver) {
14148
+ const m = receiver.match(/(?:^|\.)([A-Z]\w*)\.(\w+)\(\)$/);
14149
+ if (!m)
14150
+ return null;
14151
+ const key = `${m[1]}.${m[2]}`;
14152
+ return this.factoryReturnTypes.get(key) ?? null;
14153
+ }
14123
14154
  clear() {
14124
14155
  this.types.clear();
14125
14156
  this.nameToFqn.clear();
14126
14157
  this.subtypes.clear();
14127
14158
  this.implementations.clear();
14159
+ this.factoryReturnTypes.clear();
14128
14160
  }
14129
14161
  resolveTypeName(name2, currentPackage) {
14130
14162
  if (name2.includes("."))
@@ -14463,6 +14495,9 @@ function registerCommonLibraries(resolver) {
14463
14495
  for (const type of [...apacheHttpClient4x, ...apacheHttpClient5x]) {
14464
14496
  resolver.addType(type, "common-libraries", type.package);
14465
14497
  }
14498
+ resolver.registerFactoryReturnType("HttpClients", "createDefault", "org.apache.http.impl.client.CloseableHttpClient");
14499
+ resolver.registerFactoryReturnType("HttpClients", "createSystem", "org.apache.http.impl.client.CloseableHttpClient");
14500
+ resolver.registerFactoryReturnType("HttpClients", "createMinimal", "org.apache.http.impl.client.MinimalHttpClient");
14466
14501
  }
14467
14502
  // ../circle-ir/dist/resolution/symbol-table.js
14468
14503
  class SymbolTable {
@@ -21961,6 +21996,30 @@ class GoPlugin extends BaseLanguagePlugin {
21961
21996
  severity: "high",
21962
21997
  argPositions: [0, 2]
21963
21998
  },
21999
+ {
22000
+ method: "Get",
22001
+ class: "fasthttp",
22002
+ type: "ssrf",
22003
+ cwe: "CWE-918",
22004
+ severity: "high",
22005
+ argPositions: [1]
22006
+ },
22007
+ {
22008
+ method: "Post",
22009
+ class: "fasthttp",
22010
+ type: "ssrf",
22011
+ cwe: "CWE-918",
22012
+ severity: "high",
22013
+ argPositions: [1]
22014
+ },
22015
+ {
22016
+ method: "GetTimeout",
22017
+ class: "fasthttp",
22018
+ type: "ssrf",
22019
+ cwe: "CWE-918",
22020
+ severity: "high",
22021
+ argPositions: [1]
22022
+ },
21964
22023
  {
21965
22024
  method: "Unmarshal",
21966
22025
  class: "json",
@@ -29828,6 +29887,12 @@ function correlateDollarBraceToArgPositions(method, refs) {
29828
29887
  }
29829
29888
  }
29830
29889
  });
29890
+ const declaredNameToIndex = new Map;
29891
+ method.parameters.forEach((param, idx) => {
29892
+ if (param.name && !declaredNameToIndex.has(param.name)) {
29893
+ declaredNameToIndex.set(param.name, idx);
29894
+ }
29895
+ });
29831
29896
  const positions = new Set;
29832
29897
  for (const ref of refs) {
29833
29898
  const namedIdx = paramNameToIndex.get(ref);
@@ -29835,6 +29900,11 @@ function correlateDollarBraceToArgPositions(method, refs) {
29835
29900
  positions.add(namedIdx);
29836
29901
  continue;
29837
29902
  }
29903
+ const declaredIdx = declaredNameToIndex.get(ref);
29904
+ if (declaredIdx !== undefined) {
29905
+ positions.add(declaredIdx);
29906
+ continue;
29907
+ }
29838
29908
  const positionalIdx = parsePositionalRef(ref);
29839
29909
  if (positionalIdx !== null && positionalIdx < method.parameters.length) {
29840
29910
  positions.add(positionalIdx);
@@ -29865,11 +29935,11 @@ class MyBatisAnnotationSqlSinkPass {
29865
29935
  category = "security";
29866
29936
  run(ctx) {
29867
29937
  if (ctx.language !== "java") {
29868
- return { annotatedMethodCount: 0, addedSinkCount: 0 };
29938
+ return { annotatedMethodCount: 0, addedSinkCount: 0, declarationFindingCount: 0 };
29869
29939
  }
29870
29940
  const { types, imports, calls } = ctx.graph.ir;
29871
29941
  if (!fileImportsMyBatis(imports)) {
29872
- return { annotatedMethodCount: 0, addedSinkCount: 0 };
29942
+ return { annotatedMethodCount: 0, addedSinkCount: 0, declarationFindingCount: 0 };
29873
29943
  }
29874
29944
  const mapperMethods = [];
29875
29945
  for (const type of types) {
@@ -29898,6 +29968,7 @@ class MyBatisAnnotationSqlSinkPass {
29898
29968
  interfaceSimpleName: type.name,
29899
29969
  interfaceFqn,
29900
29970
  methodName: method.name,
29971
+ declarationLine: method.start_line,
29901
29972
  taintedArgPositions: positions
29902
29973
  });
29903
29974
  }
@@ -29905,9 +29976,27 @@ class MyBatisAnnotationSqlSinkPass {
29905
29976
  if (mapperMethods.length === 0) {
29906
29977
  return {
29907
29978
  annotatedMethodCount: 0,
29908
- addedSinkCount: 0
29979
+ addedSinkCount: 0,
29980
+ declarationFindingCount: 0
29909
29981
  };
29910
29982
  }
29983
+ const file = ctx.graph.ir.meta.file;
29984
+ let declarationFindingCount = 0;
29985
+ for (const rec of mapperMethods) {
29986
+ ctx.addFinding({
29987
+ id: `${this.name}-${file}-${rec.declarationLine}-${rec.methodName}`,
29988
+ pass: this.name,
29989
+ category: this.category,
29990
+ rule_id: this.name,
29991
+ cwe: "CWE-89",
29992
+ severity: "critical",
29993
+ level: "error",
29994
+ 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.`,
29995
+ file,
29996
+ line: rec.declarationLine
29997
+ });
29998
+ declarationFindingCount++;
29999
+ }
29911
30000
  const sinks = ctx.hasResult("taint-matcher") ? ctx.getResult("taint-matcher").sinks : ctx.graph.ir.taint.sinks;
29912
30001
  let addedSinkCount = 0;
29913
30002
  for (const call of calls) {
@@ -29935,7 +30024,8 @@ class MyBatisAnnotationSqlSinkPass {
29935
30024
  }
29936
30025
  return {
29937
30026
  annotatedMethodCount: mapperMethods.length,
29938
- addedSinkCount
30027
+ addedSinkCount,
30028
+ declarationFindingCount
29939
30029
  };
29940
30030
  }
29941
30031
  }
@@ -43751,7 +43841,7 @@ var colors = {
43751
43841
  };
43752
43842
 
43753
43843
  // src/version.ts
43754
- var version = "3.159.0";
43844
+ var version = "3.161.0";
43755
43845
 
43756
43846
  // src/formatters.ts
43757
43847
  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.161.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.161.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",