circle-ir 3.41.0 → 3.43.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.
@@ -6096,11 +6096,22 @@ function inferJSTypeFromReceiver(receiver) {
6096
6096
  function buildResolutionContext(tree, cache) {
6097
6097
  const context = {
6098
6098
  className: null,
6099
+ packageName: null,
6099
6100
  methodNames: /* @__PURE__ */ new Set(),
6100
6101
  fieldTypes: /* @__PURE__ */ new Map(),
6101
6102
  localVarTypes: /* @__PURE__ */ new Map(),
6102
- imports: /* @__PURE__ */ new Set()
6103
+ paramTypes: /* @__PURE__ */ new Map(),
6104
+ imports: /* @__PURE__ */ new Map(),
6105
+ wildcardImports: []
6103
6106
  };
6107
+ const packages = getNodesFromCache(tree.rootNode, "package_declaration", cache);
6108
+ if (packages.length > 0) {
6109
+ const text = getNodeText(packages[0]);
6110
+ const match = text.match(/package\s+([a-zA-Z0-9_.]+)/);
6111
+ if (match) {
6112
+ context.packageName = match[1];
6113
+ }
6114
+ }
6104
6115
  const classes = getNodesFromCache(tree.rootNode, "class_declaration", cache);
6105
6116
  if (classes.length > 0) {
6106
6117
  const nameNode = classes[0].childForFieldName("name");
@@ -6114,6 +6125,17 @@ function buildResolutionContext(tree, cache) {
6114
6125
  if (nameNode) {
6115
6126
  context.methodNames.add(getNodeText(nameNode));
6116
6127
  }
6128
+ const paramsNode = method.childForFieldName("parameters");
6129
+ if (paramsNode) {
6130
+ collectParameterTypes(paramsNode, context.paramTypes);
6131
+ }
6132
+ }
6133
+ const constructors = getNodesFromCache(tree.rootNode, "constructor_declaration", cache);
6134
+ for (const ctor of constructors) {
6135
+ const paramsNode = ctor.childForFieldName("parameters");
6136
+ if (paramsNode) {
6137
+ collectParameterTypes(paramsNode, context.paramTypes);
6138
+ }
6117
6139
  }
6118
6140
  const fields = getNodesFromCache(tree.rootNode, "field_declaration", cache);
6119
6141
  for (const field of fields) {
@@ -6146,14 +6168,106 @@ function buildResolutionContext(tree, cache) {
6146
6168
  const imports = getNodesFromCache(tree.rootNode, "import_declaration", cache);
6147
6169
  for (const imp of imports) {
6148
6170
  const text = getNodeText(imp);
6149
- const match = text.match(/import\s+(?:static\s+)?([a-zA-Z0-9_.]+)/);
6150
- if (match) {
6151
- const parts2 = match[1].split(".");
6152
- context.imports.add(parts2[parts2.length - 1]);
6171
+ const match = text.match(/import\s+(?:static\s+)?([a-zA-Z0-9_.]+)(\.\*)?/);
6172
+ if (!match) continue;
6173
+ const fqn = match[1];
6174
+ const isWildcard = match[2] === ".*";
6175
+ if (isWildcard) {
6176
+ context.wildcardImports.push(fqn);
6177
+ } else {
6178
+ const parts2 = fqn.split(".");
6179
+ const simple = parts2[parts2.length - 1];
6180
+ context.imports.set(simple, fqn);
6153
6181
  }
6154
6182
  }
6155
6183
  return context;
6156
6184
  }
6185
+ function collectParameterTypes(paramsNode, out2) {
6186
+ for (let i2 = 0; i2 < paramsNode.childCount; i2++) {
6187
+ const child = paramsNode.child(i2);
6188
+ if (!child) continue;
6189
+ if (child.type !== "formal_parameter" && child.type !== "spread_parameter") {
6190
+ continue;
6191
+ }
6192
+ const typeNode = child.childForFieldName("type");
6193
+ const nameNode = child.childForFieldName("name");
6194
+ if (typeNode && nameNode) {
6195
+ out2.set(getNodeText(nameNode), getNodeText(typeNode));
6196
+ }
6197
+ }
6198
+ }
6199
+ function stripGenerics(type) {
6200
+ const ltIdx = type.indexOf("<");
6201
+ return ltIdx === -1 ? type : type.substring(0, ltIdx);
6202
+ }
6203
+ function resolveReceiverType(receiver, context) {
6204
+ if (!receiver) return { simpleName: null, fqn: null };
6205
+ if (receiver === "this") {
6206
+ return resolveFqn(context.className, context);
6207
+ }
6208
+ if (receiver.startsWith("this.")) {
6209
+ const fieldName = receiver.substring("this.".length);
6210
+ const fieldType = context.fieldTypes.get(fieldName);
6211
+ if (fieldType) return resolveFqn(stripGenerics(fieldType), context);
6212
+ return { simpleName: null, fqn: null };
6213
+ }
6214
+ if (receiver === "super") return { simpleName: null, fqn: null };
6215
+ const declaredType = context.localVarTypes.get(receiver) ?? context.paramTypes.get(receiver) ?? context.fieldTypes.get(receiver);
6216
+ if (declaredType) {
6217
+ return resolveFqn(stripGenerics(declaredType), context);
6218
+ }
6219
+ if (/^[A-Z]/.test(receiver)) {
6220
+ const simple = receiver.includes(".") ? receiver.substring(receiver.lastIndexOf(".") + 1) : receiver;
6221
+ if (/^[A-Z][A-Za-z0-9_]*$/.test(simple)) {
6222
+ return resolveFqn(simple, context);
6223
+ }
6224
+ }
6225
+ return { simpleName: null, fqn: null };
6226
+ }
6227
+ function resolveFqn(simpleName, context) {
6228
+ if (!simpleName) return { simpleName: null, fqn: null };
6229
+ const importedFqn = context.imports.get(simpleName);
6230
+ if (importedFqn) {
6231
+ return { simpleName, fqn: importedFqn };
6232
+ }
6233
+ if (context.className === simpleName && context.packageName) {
6234
+ return { simpleName, fqn: `${context.packageName}.${simpleName}` };
6235
+ }
6236
+ if (JAVA_LANG_TYPES.has(simpleName)) {
6237
+ return { simpleName, fqn: `java.lang.${simpleName}` };
6238
+ }
6239
+ return { simpleName, fqn: null };
6240
+ }
6241
+ var JAVA_LANG_TYPES = /* @__PURE__ */ new Set([
6242
+ "String",
6243
+ "StringBuilder",
6244
+ "StringBuffer",
6245
+ "Object",
6246
+ "Class",
6247
+ "Integer",
6248
+ "Long",
6249
+ "Double",
6250
+ "Float",
6251
+ "Boolean",
6252
+ "Character",
6253
+ "Byte",
6254
+ "Short",
6255
+ "Number",
6256
+ "Math",
6257
+ "System",
6258
+ "Thread",
6259
+ "Runnable",
6260
+ "Throwable",
6261
+ "Exception",
6262
+ "RuntimeException",
6263
+ "Error",
6264
+ "Process",
6265
+ "ProcessBuilder",
6266
+ "Iterable",
6267
+ "Comparable",
6268
+ "CharSequence",
6269
+ "Enum"
6270
+ ]);
6157
6271
  function extractCallInfo(node, context) {
6158
6272
  const nameNode = node.childForFieldName("name");
6159
6273
  const methodName = nameNode ? getNodeText(nameNode) : "unknown";
@@ -6163,9 +6277,12 @@ function extractCallInfo(node, context) {
6163
6277
  const args2 = argsNode ? extractArguments(argsNode) : [];
6164
6278
  const enclosingMethod = findEnclosingMethod(node);
6165
6279
  const { resolved, resolution } = resolveMethodCall(methodName, receiver, context);
6280
+ const { simpleName, fqn } = resolveReceiverType(receiver, context);
6166
6281
  return {
6167
6282
  method_name: methodName,
6168
6283
  receiver,
6284
+ receiver_type: simpleName,
6285
+ receiver_type_fqn: fqn,
6169
6286
  arguments: args2,
6170
6287
  location: {
6171
6288
  line: node.startPosition.row + 1,
@@ -6187,10 +6304,14 @@ function extractObjectCreation(node, context) {
6187
6304
  status: "resolved",
6188
6305
  target: `${typeName}.<init>`
6189
6306
  };
6307
+ const simpleType = stripGenerics(typeName);
6308
+ const { simpleName, fqn } = resolveFqn(simpleType, context);
6190
6309
  return {
6191
6310
  method_name: typeName,
6192
6311
  // Constructor name is the class name
6193
6312
  receiver: null,
6313
+ receiver_type: simpleName,
6314
+ receiver_type_fqn: fqn,
6194
6315
  arguments: args2,
6195
6316
  location: {
6196
6317
  line: node.startPosition.row + 1,
@@ -10123,6 +10244,23 @@ var DEFAULT_SINKS = [
10123
10244
  { method: "queryForObject", type: "sql_injection", cwe: "CWE-89", severity: "high", arg_positions: [0] },
10124
10245
  { method: "queryForList", type: "sql_injection", cwe: "CWE-89", severity: "high", arg_positions: [0] },
10125
10246
  { method: "queryForLong", type: "sql_injection", cwe: "CWE-89", severity: "high", arg_positions: [0] },
10247
+ // MyBatis mapper-interface methods (CWE-89, classified as mybatis_mapper_call)
10248
+ // The actual SQL lives in the mapper's XML or @Select/@Update annotation —
10249
+ // exploitability depends on whether the binding uses ${...} interpolation
10250
+ // vs #{...} parameter binding. Surface as a distinct sink type so consumers
10251
+ // can resolve the binding before reporting. See cognium-dev#24.
10252
+ // The `class: '*Mapper'` suffix wildcard matches userMapper, OrderMapper, …
10253
+ { method: "insert", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10254
+ { method: "insertSelective", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10255
+ { method: "update", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10256
+ { method: "updateByPrimaryKey", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10257
+ { method: "updateByPrimaryKeySelective", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10258
+ { method: "delete", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10259
+ { method: "deleteByPrimaryKey", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10260
+ { method: "selectOne", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10261
+ { method: "selectList", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10262
+ { method: "selectByPrimaryKey", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10263
+ { method: "selectByExample", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10126
10264
  // Command Injection (CWE-78)
10127
10265
  { method: "exec", class: "Runtime", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
10128
10266
  { method: "start", class: "ProcessBuilder", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [] },
@@ -12017,6 +12155,14 @@ function matchesAnnotation(annotations, targetAnnotation) {
12017
12155
  return false;
12018
12156
  }
12019
12157
  function receiverMightBeClass(receiver, className) {
12158
+ if (className.startsWith("*") && className.length > 1) {
12159
+ const suffix = className.slice(1).toLowerCase();
12160
+ let simpleReceiver = receiver;
12161
+ if (simpleReceiver.includes(".") && !simpleReceiver.endsWith(")")) {
12162
+ simpleReceiver = simpleReceiver.substring(simpleReceiver.lastIndexOf(".") + 1);
12163
+ }
12164
+ return simpleReceiver.toLowerCase().endsWith(suffix);
12165
+ }
12020
12166
  if (receiver === className) {
12021
12167
  return true;
12022
12168
  }
@@ -12790,7 +12936,8 @@ var KNOWN_SINK_TYPES = /* @__PURE__ */ new Set([
12790
12936
  "log_injection",
12791
12937
  "xxe",
12792
12938
  "deserialization",
12793
- "code_injection"
12939
+ "code_injection",
12940
+ "mybatis_mapper_call"
12794
12941
  ]);
12795
12942
  function checkSanitized(_fromLine, toLine, sinkType, sanitizersByLine) {
12796
12943
  const sanitizersAtTarget = sanitizersByLine.get(toLine);
@@ -6030,11 +6030,22 @@ function inferJSTypeFromReceiver(receiver) {
6030
6030
  function buildResolutionContext(tree, cache) {
6031
6031
  const context = {
6032
6032
  className: null,
6033
+ packageName: null,
6033
6034
  methodNames: /* @__PURE__ */ new Set(),
6034
6035
  fieldTypes: /* @__PURE__ */ new Map(),
6035
6036
  localVarTypes: /* @__PURE__ */ new Map(),
6036
- imports: /* @__PURE__ */ new Set()
6037
+ paramTypes: /* @__PURE__ */ new Map(),
6038
+ imports: /* @__PURE__ */ new Map(),
6039
+ wildcardImports: []
6037
6040
  };
6041
+ const packages = getNodesFromCache(tree.rootNode, "package_declaration", cache);
6042
+ if (packages.length > 0) {
6043
+ const text = getNodeText(packages[0]);
6044
+ const match = text.match(/package\s+([a-zA-Z0-9_.]+)/);
6045
+ if (match) {
6046
+ context.packageName = match[1];
6047
+ }
6048
+ }
6038
6049
  const classes = getNodesFromCache(tree.rootNode, "class_declaration", cache);
6039
6050
  if (classes.length > 0) {
6040
6051
  const nameNode = classes[0].childForFieldName("name");
@@ -6048,6 +6059,17 @@ function buildResolutionContext(tree, cache) {
6048
6059
  if (nameNode) {
6049
6060
  context.methodNames.add(getNodeText(nameNode));
6050
6061
  }
6062
+ const paramsNode = method.childForFieldName("parameters");
6063
+ if (paramsNode) {
6064
+ collectParameterTypes(paramsNode, context.paramTypes);
6065
+ }
6066
+ }
6067
+ const constructors = getNodesFromCache(tree.rootNode, "constructor_declaration", cache);
6068
+ for (const ctor of constructors) {
6069
+ const paramsNode = ctor.childForFieldName("parameters");
6070
+ if (paramsNode) {
6071
+ collectParameterTypes(paramsNode, context.paramTypes);
6072
+ }
6051
6073
  }
6052
6074
  const fields = getNodesFromCache(tree.rootNode, "field_declaration", cache);
6053
6075
  for (const field of fields) {
@@ -6080,14 +6102,106 @@ function buildResolutionContext(tree, cache) {
6080
6102
  const imports = getNodesFromCache(tree.rootNode, "import_declaration", cache);
6081
6103
  for (const imp of imports) {
6082
6104
  const text = getNodeText(imp);
6083
- const match = text.match(/import\s+(?:static\s+)?([a-zA-Z0-9_.]+)/);
6084
- if (match) {
6085
- const parts2 = match[1].split(".");
6086
- context.imports.add(parts2[parts2.length - 1]);
6105
+ const match = text.match(/import\s+(?:static\s+)?([a-zA-Z0-9_.]+)(\.\*)?/);
6106
+ if (!match) continue;
6107
+ const fqn = match[1];
6108
+ const isWildcard = match[2] === ".*";
6109
+ if (isWildcard) {
6110
+ context.wildcardImports.push(fqn);
6111
+ } else {
6112
+ const parts2 = fqn.split(".");
6113
+ const simple = parts2[parts2.length - 1];
6114
+ context.imports.set(simple, fqn);
6087
6115
  }
6088
6116
  }
6089
6117
  return context;
6090
6118
  }
6119
+ function collectParameterTypes(paramsNode, out2) {
6120
+ for (let i2 = 0; i2 < paramsNode.childCount; i2++) {
6121
+ const child = paramsNode.child(i2);
6122
+ if (!child) continue;
6123
+ if (child.type !== "formal_parameter" && child.type !== "spread_parameter") {
6124
+ continue;
6125
+ }
6126
+ const typeNode = child.childForFieldName("type");
6127
+ const nameNode = child.childForFieldName("name");
6128
+ if (typeNode && nameNode) {
6129
+ out2.set(getNodeText(nameNode), getNodeText(typeNode));
6130
+ }
6131
+ }
6132
+ }
6133
+ function stripGenerics(type) {
6134
+ const ltIdx = type.indexOf("<");
6135
+ return ltIdx === -1 ? type : type.substring(0, ltIdx);
6136
+ }
6137
+ function resolveReceiverType(receiver, context) {
6138
+ if (!receiver) return { simpleName: null, fqn: null };
6139
+ if (receiver === "this") {
6140
+ return resolveFqn(context.className, context);
6141
+ }
6142
+ if (receiver.startsWith("this.")) {
6143
+ const fieldName = receiver.substring("this.".length);
6144
+ const fieldType = context.fieldTypes.get(fieldName);
6145
+ if (fieldType) return resolveFqn(stripGenerics(fieldType), context);
6146
+ return { simpleName: null, fqn: null };
6147
+ }
6148
+ if (receiver === "super") return { simpleName: null, fqn: null };
6149
+ const declaredType = context.localVarTypes.get(receiver) ?? context.paramTypes.get(receiver) ?? context.fieldTypes.get(receiver);
6150
+ if (declaredType) {
6151
+ return resolveFqn(stripGenerics(declaredType), context);
6152
+ }
6153
+ if (/^[A-Z]/.test(receiver)) {
6154
+ const simple = receiver.includes(".") ? receiver.substring(receiver.lastIndexOf(".") + 1) : receiver;
6155
+ if (/^[A-Z][A-Za-z0-9_]*$/.test(simple)) {
6156
+ return resolveFqn(simple, context);
6157
+ }
6158
+ }
6159
+ return { simpleName: null, fqn: null };
6160
+ }
6161
+ function resolveFqn(simpleName, context) {
6162
+ if (!simpleName) return { simpleName: null, fqn: null };
6163
+ const importedFqn = context.imports.get(simpleName);
6164
+ if (importedFqn) {
6165
+ return { simpleName, fqn: importedFqn };
6166
+ }
6167
+ if (context.className === simpleName && context.packageName) {
6168
+ return { simpleName, fqn: `${context.packageName}.${simpleName}` };
6169
+ }
6170
+ if (JAVA_LANG_TYPES.has(simpleName)) {
6171
+ return { simpleName, fqn: `java.lang.${simpleName}` };
6172
+ }
6173
+ return { simpleName, fqn: null };
6174
+ }
6175
+ var JAVA_LANG_TYPES = /* @__PURE__ */ new Set([
6176
+ "String",
6177
+ "StringBuilder",
6178
+ "StringBuffer",
6179
+ "Object",
6180
+ "Class",
6181
+ "Integer",
6182
+ "Long",
6183
+ "Double",
6184
+ "Float",
6185
+ "Boolean",
6186
+ "Character",
6187
+ "Byte",
6188
+ "Short",
6189
+ "Number",
6190
+ "Math",
6191
+ "System",
6192
+ "Thread",
6193
+ "Runnable",
6194
+ "Throwable",
6195
+ "Exception",
6196
+ "RuntimeException",
6197
+ "Error",
6198
+ "Process",
6199
+ "ProcessBuilder",
6200
+ "Iterable",
6201
+ "Comparable",
6202
+ "CharSequence",
6203
+ "Enum"
6204
+ ]);
6091
6205
  function extractCallInfo(node, context) {
6092
6206
  const nameNode = node.childForFieldName("name");
6093
6207
  const methodName = nameNode ? getNodeText(nameNode) : "unknown";
@@ -6097,9 +6211,12 @@ function extractCallInfo(node, context) {
6097
6211
  const args2 = argsNode ? extractArguments(argsNode) : [];
6098
6212
  const enclosingMethod = findEnclosingMethod(node);
6099
6213
  const { resolved, resolution } = resolveMethodCall(methodName, receiver, context);
6214
+ const { simpleName, fqn } = resolveReceiverType(receiver, context);
6100
6215
  return {
6101
6216
  method_name: methodName,
6102
6217
  receiver,
6218
+ receiver_type: simpleName,
6219
+ receiver_type_fqn: fqn,
6103
6220
  arguments: args2,
6104
6221
  location: {
6105
6222
  line: node.startPosition.row + 1,
@@ -6121,10 +6238,14 @@ function extractObjectCreation(node, context) {
6121
6238
  status: "resolved",
6122
6239
  target: `${typeName}.<init>`
6123
6240
  };
6241
+ const simpleType = stripGenerics(typeName);
6242
+ const { simpleName, fqn } = resolveFqn(simpleType, context);
6124
6243
  return {
6125
6244
  method_name: typeName,
6126
6245
  // Constructor name is the class name
6127
6246
  receiver: null,
6247
+ receiver_type: simpleName,
6248
+ receiver_type_fqn: fqn,
6128
6249
  arguments: args2,
6129
6250
  location: {
6130
6251
  line: node.startPosition.row + 1,
@@ -10057,6 +10178,23 @@ var DEFAULT_SINKS = [
10057
10178
  { method: "queryForObject", type: "sql_injection", cwe: "CWE-89", severity: "high", arg_positions: [0] },
10058
10179
  { method: "queryForList", type: "sql_injection", cwe: "CWE-89", severity: "high", arg_positions: [0] },
10059
10180
  { method: "queryForLong", type: "sql_injection", cwe: "CWE-89", severity: "high", arg_positions: [0] },
10181
+ // MyBatis mapper-interface methods (CWE-89, classified as mybatis_mapper_call)
10182
+ // The actual SQL lives in the mapper's XML or @Select/@Update annotation —
10183
+ // exploitability depends on whether the binding uses ${...} interpolation
10184
+ // vs #{...} parameter binding. Surface as a distinct sink type so consumers
10185
+ // can resolve the binding before reporting. See cognium-dev#24.
10186
+ // The `class: '*Mapper'` suffix wildcard matches userMapper, OrderMapper, …
10187
+ { method: "insert", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10188
+ { method: "insertSelective", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10189
+ { method: "update", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10190
+ { method: "updateByPrimaryKey", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10191
+ { method: "updateByPrimaryKeySelective", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10192
+ { method: "delete", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10193
+ { method: "deleteByPrimaryKey", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10194
+ { method: "selectOne", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10195
+ { method: "selectList", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10196
+ { method: "selectByPrimaryKey", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10197
+ { method: "selectByExample", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
10060
10198
  // Command Injection (CWE-78)
10061
10199
  { method: "exec", class: "Runtime", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
10062
10200
  { method: "start", class: "ProcessBuilder", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [] },
@@ -11951,6 +12089,14 @@ function matchesAnnotation(annotations, targetAnnotation) {
11951
12089
  return false;
11952
12090
  }
11953
12091
  function receiverMightBeClass(receiver, className) {
12092
+ if (className.startsWith("*") && className.length > 1) {
12093
+ const suffix = className.slice(1).toLowerCase();
12094
+ let simpleReceiver = receiver;
12095
+ if (simpleReceiver.includes(".") && !simpleReceiver.endsWith(")")) {
12096
+ simpleReceiver = simpleReceiver.substring(simpleReceiver.lastIndexOf(".") + 1);
12097
+ }
12098
+ return simpleReceiver.toLowerCase().endsWith(suffix);
12099
+ }
11954
12100
  if (receiver === className) {
11955
12101
  return true;
11956
12102
  }
@@ -12724,7 +12870,8 @@ var KNOWN_SINK_TYPES = /* @__PURE__ */ new Set([
12724
12870
  "log_injection",
12725
12871
  "xxe",
12726
12872
  "deserialization",
12727
- "code_injection"
12873
+ "code_injection",
12874
+ "mybatis_mapper_call"
12728
12875
  ]);
12729
12876
  function checkSanitized(_fromLine, toLine, sinkType, sanitizersByLine) {
12730
12877
  const sanitizersAtTarget = sanitizersByLine.get(toLine);
@@ -1 +1 @@
1
- {"version":3,"file":"calls.d.ts","sourceRoot":"","sources":["../../../src/core/extractors/calls.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAQ,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAgC,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAA2D,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAkEvG;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,EAAE,CAgDzF"}
1
+ {"version":3,"file":"calls.d.ts","sourceRoot":"","sources":["../../../src/core/extractors/calls.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAQ,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAgC,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAA2D,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AA8EvG;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,EAAE,CAgDzF"}