circle-ir 3.18.6 → 3.18.8

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.
@@ -9107,6 +9107,7 @@ var DEFAULT_SOURCES = [
9107
9107
  { method: "lines", class: "BufReader", type: "file_input", severity: "medium", return_tainted: true },
9108
9108
  { method: "read_to_string", class: "stdin", type: "io_input", severity: "medium", return_tainted: true },
9109
9109
  { method: "read_line", class: "stdin", type: "io_input", severity: "medium", return_tainted: true },
9110
+ { method: "lines", class: "stdin", type: "io_input", severity: "medium", return_tainted: true },
9110
9111
  { method: "recv", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
9111
9112
  { method: "read", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
9112
9113
  { method: "read_to_end", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
@@ -9618,6 +9619,38 @@ var DEFAULT_SINKS = [
9618
9619
  { method: "processRequest", class: "Broker", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9619
9620
  // DolphinScheduler
9620
9621
  { method: "execute", class: "TaskExecuteThread", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9622
+ // Apache Commons JEXL (JEXL expression injection)
9623
+ { method: "createExpression", class: "JexlEngine", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9624
+ { method: "createScript", class: "JexlEngine", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9625
+ { method: "evaluate", class: "JexlExpression", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [] },
9626
+ { method: "execute", class: "JexlScript", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [] },
9627
+ // Janino expression evaluator (Calcite/Flink/Drill)
9628
+ { method: "createFastEvaluator", class: "ExpressionEvaluator", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9629
+ { method: "cook", class: "ExpressionEvaluator", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9630
+ { method: "cook", class: "ScriptEvaluator", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9631
+ { method: "cook", class: "ClassBodyEvaluator", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9632
+ { method: "cook", class: "SimpleCompiler", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9633
+ // Apache Camel Simple language (CVE-2018-8041 and similar)
9634
+ { method: "createExpression", class: "SimpleLanguage", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9635
+ { method: "createPredicate", class: "SimpleLanguage", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9636
+ // Thymeleaf StandardExpression (CVE-2023-38286 and similar)
9637
+ { method: "parseExpression", class: "StandardExpressionParser", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [1] },
9638
+ { method: "getValue", class: "StandardExpression", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [] },
9639
+ // FreeMarker direct template construction (CVE-2022-26336 and similar)
9640
+ { method: "Template", class: "Template", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [1] },
9641
+ // new Template(name, tainted)
9642
+ { method: "getTemplate", class: "Configuration", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0] },
9643
+ // Jinjava (Java Jinja template engine)
9644
+ { method: "render", class: "Jinjava", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0] },
9645
+ { method: "renderForResult", class: "Jinjava", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0] },
9646
+ // Spring Cloud Function RoutingFunction (CVE-2022-22963)
9647
+ { method: "getRequestedBeanName", class: "RoutingFunction", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [] },
9648
+ // Kotlin reflection (RCE via reflective construction)
9649
+ { method: "createInstance", class: "KClass", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [] },
9650
+ { method: "callBy", class: "KFunction", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0] },
9651
+ // Struts 2 deep injection (CVE-2017-5638 and descendants)
9652
+ { method: "translateVariables", class: "TextParseUtil", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9653
+ { method: "evaluate", class: "StrutsResultSupport", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9621
9654
  // Deserialization (CWE-502)
9622
9655
  { method: "readObject", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [] },
9623
9656
  { method: "readUnshared", class: "ObjectInputStream", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [] },
@@ -9627,9 +9660,8 @@ var DEFAULT_SINKS = [
9627
9660
  { method: "load", class: "Yaml", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0] },
9628
9661
  { method: "loadAll", class: "Yaml", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0] },
9629
9662
  { method: "loadAs", class: "Yaml", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0] },
9630
- // JSON deserialization
9663
+ // JSON deserialization (Java FastJSON / Jackson — NOT JavaScript's safe JSON.parse)
9631
9664
  { method: "parseObject", class: "JSON", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0] },
9632
- { method: "parse", class: "JSON", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0] },
9633
9665
  { method: "parseObject", class: "JSONObject", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0] },
9634
9666
  { method: "fromJson", class: "Gson", type: "deserialization", cwe: "CWE-502", severity: "medium", arg_positions: [0] },
9635
9667
  // XMLDecoder
@@ -9662,8 +9694,8 @@ var DEFAULT_SINKS = [
9662
9694
  { method: "sendRedirect", type: "ssrf", cwe: "CWE-601", severity: "high", arg_positions: [0] },
9663
9695
  { method: "openConnection", class: "URL", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [] },
9664
9696
  { method: "openStream", class: "URL", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [] },
9665
- { method: "URL", class: "constructor", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
9666
- { method: "URI", class: "constructor", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
9697
+ // NOTE: URL/URI constructors removed constructing a URL object doesn't make a network
9698
+ // request in any language. The real SSRF sinks are openConnection/openStream/execute/etc.
9667
9699
  { method: "execute", class: "HttpClient", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
9668
9700
  { method: "send", class: "HttpClient", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
9669
9701
  { method: "getForObject", class: "RestTemplate", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
@@ -10140,6 +10172,17 @@ var DEFAULT_SANITIZERS = [
10140
10172
  { method: "encodeForHTML", removes: ["xss"] },
10141
10173
  { method: "escapeXml", removes: ["xss"] },
10142
10174
  { method: "htmlEscape", removes: ["xss"] },
10175
+ { method: "escapeHtml4", removes: ["xss"] },
10176
+ // Apache Commons StringEscapeUtils
10177
+ { method: "escapeHtml3", removes: ["xss"] },
10178
+ // Apache Commons StringEscapeUtils
10179
+ { method: "htmlSpecialChars", removes: ["xss"] },
10180
+ // PHP-style / common wrapper
10181
+ { method: "forHtml", class: "Encode", removes: ["xss"] },
10182
+ // OWASP Java Encoder
10183
+ { method: "forHtmlContent", class: "Encode", removes: ["xss"] },
10184
+ { method: "forHtmlAttribute", class: "Encode", removes: ["xss"] },
10185
+ { method: "forJavaScript", class: "Encode", removes: ["xss"] },
10143
10186
  { method: "encode_text", removes: ["xss"] },
10144
10187
  // Rust html_escape crate
10145
10188
  { method: "encode_safe", removes: ["xss"] },
@@ -10149,6 +10192,11 @@ var DEFAULT_SANITIZERS = [
10149
10192
  { method: "encodeForJavaScript", removes: ["xss"] },
10150
10193
  { method: "encodeForCSS", removes: ["xss"] },
10151
10194
  { method: "encodeForURL", removes: ["xss", "ssrf"] },
10195
+ // URL encoding wrapper aliases (common patterns in benchmarks and real-world code)
10196
+ { method: "encodeURL", removes: ["xss", "ssrf"] },
10197
+ { method: "urlEncode", removes: ["xss", "ssrf"] },
10198
+ { method: "escapeUrl", removes: ["xss", "ssrf"] },
10199
+ { method: "escapeURL", removes: ["xss", "ssrf"] },
10152
10200
  // Path Traversal
10153
10201
  { method: "normalize", class: "Path", removes: ["path_traversal"] },
10154
10202
  { method: "getCanonicalPath", class: "File", removes: ["path_traversal"] },
@@ -10266,11 +10314,11 @@ var DEFAULT_SANITIZERS = [
10266
10314
  { method: "canonicalize", removes: ["path_traversal"] },
10267
10315
  // Resolves symlinks, validates path exists
10268
10316
  // Rust Command Injection - allowlist validation
10269
- { method: "contains", removes: ["command_injection", "ssrf"] },
10317
+ { method: "contains", removes: ["command_injection", "ssrf", "open_redirect"] },
10270
10318
  // Used for allowlist checks
10271
- { method: "starts_with", removes: ["path_traversal", "ssrf"] },
10319
+ { method: "starts_with", removes: ["path_traversal", "ssrf", "open_redirect"] },
10272
10320
  // Path/URL prefix validation
10273
- { method: "ends_with", removes: ["path_traversal"] },
10321
+ { method: "ends_with", removes: ["path_traversal", "open_redirect"] },
10274
10322
  // Rust XSS - HTML escaping
10275
10323
  { method: "escape", class: "html_escape", removes: ["xss"] },
10276
10324
  { method: "encode_text", class: "html_escape", removes: ["xss"] },
@@ -10345,6 +10393,26 @@ function findSources(calls, types, patterns) {
10345
10393
  }
10346
10394
  }
10347
10395
  }
10396
+ const RUST_EXTRACTOR_TYPES = /^(?:Json|Form|Query|Path|Extension|Multipart)(?:<|$)|^(?:Body|Bytes)$/;
10397
+ for (const type of types) {
10398
+ for (const method of type.methods) {
10399
+ for (const param of method.parameters) {
10400
+ if (param.type && RUST_EXTRACTOR_TYPES.test(param.type)) {
10401
+ const paramLine = param.line ?? method.start_line;
10402
+ const alreadyExists = sources.some((s) => s.line === paramLine && s.type === "http_body");
10403
+ if (!alreadyExists) {
10404
+ sources.push({
10405
+ type: "http_body",
10406
+ location: `${param.type} ${param.name} in ${method.name}`,
10407
+ severity: "high",
10408
+ line: paramLine,
10409
+ confidence: 1
10410
+ });
10411
+ }
10412
+ }
10413
+ }
10414
+ }
10415
+ }
10348
10416
  for (const type of types) {
10349
10417
  for (const method of type.methods) {
10350
10418
  if (method.modifiers.includes("private")) continue;
@@ -10722,7 +10790,8 @@ function receiverMightBeClass(receiver, className) {
10722
10790
  "prepareStatement": ["PreparedStatement"],
10723
10791
  "getRuntime": ["Runtime"],
10724
10792
  "builder": ["Response", "ResponseBuilder", "HttpResponseBuilder"],
10725
- "stdin": ["stdin", "Stdin", "BufReader"]
10793
+ "stdin": ["stdin", "Stdin", "BufReader"],
10794
+ "lock": ["stdin", "Stdin", "StdinLock", "BufReader"]
10726
10795
  };
10727
10796
  const expectedTypes = returnTypeMappings[methodName];
10728
10797
  if (Array.isArray(expectedTypes) && expectedTypes.includes(className)) {
@@ -16463,15 +16532,8 @@ var JavaScriptPlugin = class extends BaseLanguagePlugin {
16463
16532
  // =========================================================
16464
16533
  // Data Exposure Sinks (React Native)
16465
16534
  // =========================================================
16466
- {
16467
- // Logging sensitive data
16468
- method: "log",
16469
- class: "console",
16470
- type: "information_exposure",
16471
- cwe: "CWE-532",
16472
- severity: "low",
16473
- argPositions: [0]
16474
- },
16535
+ // NOTE: console.log removed as a sink — too noisy for general-purpose analysis.
16536
+ // console.log is ubiquitous and rarely a true vulnerability outside mobile contexts.
16475
16537
  {
16476
16538
  // Storing sensitive data insecurely
16477
16539
  method: "setItem",
@@ -18394,7 +18456,14 @@ var JS_TAINTED_PATTERNS = [
18394
18456
  { pattern: /\bwindow\.name\b/, type: "dom_input" },
18395
18457
  { pattern: /\bdocument\.URL\b/, type: "http_path" },
18396
18458
  { pattern: /\bdocument\.documentURI\b/, type: "http_path" },
18397
- { pattern: /\blocation\.pathname\b/, type: "http_path" }
18459
+ { pattern: /\blocation\.pathname\b/, type: "http_path" },
18460
+ // DOM propagation globals - deprecated/obscure but still exploitable as taint conduits.
18461
+ // Writing attacker-controlled data here and reading it back preserves taint (DOMPropagation pattern).
18462
+ { pattern: /\bwindow\.status\b/, type: "dom_input" },
18463
+ { pattern: /\bdocument\.title\b/, type: "dom_input" },
18464
+ { pattern: /\bhistory\.state\b/, type: "dom_input" },
18465
+ { pattern: /\blocalStorage\.getItem\b/, type: "dom_input" },
18466
+ { pattern: /\bsessionStorage\.getItem\b/, type: "dom_input" }
18398
18467
  ];
18399
18468
  var PYTHON_TAINTED_PATTERNS2 = [
18400
18469
  { pattern: /\brequest\.args\b/, type: "http_param" },
@@ -18823,7 +18892,8 @@ var SinkFilterPass = class {
18823
18892
  constProp.symbols,
18824
18893
  dfg,
18825
18894
  constProp.sanitizedVars,
18826
- constProp.synchronizedLines
18895
+ constProp.synchronizedLines,
18896
+ language
18827
18897
  );
18828
18898
  filtered = filterSanitizedSinks(filtered, sanitizers, calls);
18829
18899
  if (language === "python") {
@@ -18881,6 +18951,16 @@ var SinkFilterPass = class {
18881
18951
  if (/^`[^`]*`$/.test(rhs) && !rhs.includes("${")) return false;
18882
18952
  if (rhs === '""' || rhs === "''" || rhs === "``") return false;
18883
18953
  }
18954
+ if (/\.href\s*=|location\s*=/.test(sinkLineText)) {
18955
+ const guardPatterns = /\b(?:includes|startsWith|endsWith|indexOf|test|match)\s*\(/;
18956
+ const startLine = Math.max(0, sink.line - 6);
18957
+ for (let i2 = startLine; i2 < sink.line - 1; i2++) {
18958
+ const line = sourceLines[i2] ?? "";
18959
+ if (/\bif\s*\(/.test(line) && guardPatterns.test(line)) {
18960
+ return false;
18961
+ }
18962
+ }
18963
+ }
18884
18964
  if (jsTaintedVars.size > 0) {
18885
18965
  if ([...jsTaintedVars.keys()].some((v) => new RegExp(`\\b${v}\\b`).test(sinkLineText))) return true;
18886
18966
  if (JS_TAINTED_PATTERNS.some((p) => p.pattern.test(sinkLineText))) return true;
@@ -19013,7 +19093,7 @@ function filterCleanArraySinks(sinks, calls, taintedArrayElements, symbols) {
19013
19093
  return true;
19014
19094
  });
19015
19095
  }
19016
- function filterCleanVariableSinks(sinks, calls, taintedVars, symbols, dfg, sanitizedVars, synchronizedLines) {
19096
+ function filterCleanVariableSinks(sinks, calls, taintedVars, symbols, dfg, sanitizedVars, synchronizedLines, language) {
19017
19097
  const fieldNames = /* @__PURE__ */ new Set();
19018
19098
  if (dfg) {
19019
19099
  for (const def of dfg.defs) {
@@ -19034,7 +19114,7 @@ function filterCleanVariableSinks(sinks, calls, taintedVars, symbols, dfg, sanit
19034
19114
  let allArgsAreClean = true;
19035
19115
  const methodName = call.in_method;
19036
19116
  for (const arg of call.arguments) {
19037
- if (arg.expression === call.method_name && !arg.variable && arg.literal == null) continue;
19117
+ if (language === "bash" && arg.expression === call.method_name && !arg.variable && arg.literal == null) continue;
19038
19118
  if (arg.variable && !arg.expression?.includes("[")) {
19039
19119
  const varName = arg.variable;
19040
19120
  const scopedName = methodName ? `${methodName}:${varName}` : varName;
@@ -9220,6 +9220,7 @@ var DEFAULT_SOURCES = [
9220
9220
  { method: "lines", class: "BufReader", type: "file_input", severity: "medium", return_tainted: true },
9221
9221
  { method: "read_to_string", class: "stdin", type: "io_input", severity: "medium", return_tainted: true },
9222
9222
  { method: "read_line", class: "stdin", type: "io_input", severity: "medium", return_tainted: true },
9223
+ { method: "lines", class: "stdin", type: "io_input", severity: "medium", return_tainted: true },
9223
9224
  { method: "recv", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
9224
9225
  { method: "read", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
9225
9226
  { method: "read_to_end", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
@@ -9731,6 +9732,38 @@ var DEFAULT_SINKS = [
9731
9732
  { method: "processRequest", class: "Broker", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9732
9733
  // DolphinScheduler
9733
9734
  { method: "execute", class: "TaskExecuteThread", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9735
+ // Apache Commons JEXL (JEXL expression injection)
9736
+ { method: "createExpression", class: "JexlEngine", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9737
+ { method: "createScript", class: "JexlEngine", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9738
+ { method: "evaluate", class: "JexlExpression", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [] },
9739
+ { method: "execute", class: "JexlScript", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [] },
9740
+ // Janino expression evaluator (Calcite/Flink/Drill)
9741
+ { method: "createFastEvaluator", class: "ExpressionEvaluator", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9742
+ { method: "cook", class: "ExpressionEvaluator", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9743
+ { method: "cook", class: "ScriptEvaluator", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9744
+ { method: "cook", class: "ClassBodyEvaluator", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9745
+ { method: "cook", class: "SimpleCompiler", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9746
+ // Apache Camel Simple language (CVE-2018-8041 and similar)
9747
+ { method: "createExpression", class: "SimpleLanguage", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9748
+ { method: "createPredicate", class: "SimpleLanguage", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9749
+ // Thymeleaf StandardExpression (CVE-2023-38286 and similar)
9750
+ { method: "parseExpression", class: "StandardExpressionParser", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [1] },
9751
+ { method: "getValue", class: "StandardExpression", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [] },
9752
+ // FreeMarker direct template construction (CVE-2022-26336 and similar)
9753
+ { method: "Template", class: "Template", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [1] },
9754
+ // new Template(name, tainted)
9755
+ { method: "getTemplate", class: "Configuration", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0] },
9756
+ // Jinjava (Java Jinja template engine)
9757
+ { method: "render", class: "Jinjava", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0] },
9758
+ { method: "renderForResult", class: "Jinjava", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0] },
9759
+ // Spring Cloud Function RoutingFunction (CVE-2022-22963)
9760
+ { method: "getRequestedBeanName", class: "RoutingFunction", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [] },
9761
+ // Kotlin reflection (RCE via reflective construction)
9762
+ { method: "createInstance", class: "KClass", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [] },
9763
+ { method: "callBy", class: "KFunction", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0] },
9764
+ // Struts 2 deep injection (CVE-2017-5638 and descendants)
9765
+ { method: "translateVariables", class: "TextParseUtil", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9766
+ { method: "evaluate", class: "StrutsResultSupport", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9734
9767
  // Deserialization (CWE-502)
9735
9768
  { method: "readObject", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [] },
9736
9769
  { method: "readUnshared", class: "ObjectInputStream", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [] },
@@ -9740,9 +9773,8 @@ var DEFAULT_SINKS = [
9740
9773
  { method: "load", class: "Yaml", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0] },
9741
9774
  { method: "loadAll", class: "Yaml", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0] },
9742
9775
  { method: "loadAs", class: "Yaml", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0] },
9743
- // JSON deserialization
9776
+ // JSON deserialization (Java FastJSON / Jackson — NOT JavaScript's safe JSON.parse)
9744
9777
  { method: "parseObject", class: "JSON", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0] },
9745
- { method: "parse", class: "JSON", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0] },
9746
9778
  { method: "parseObject", class: "JSONObject", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0] },
9747
9779
  { method: "fromJson", class: "Gson", type: "deserialization", cwe: "CWE-502", severity: "medium", arg_positions: [0] },
9748
9780
  // XMLDecoder
@@ -9775,8 +9807,8 @@ var DEFAULT_SINKS = [
9775
9807
  { method: "sendRedirect", type: "ssrf", cwe: "CWE-601", severity: "high", arg_positions: [0] },
9776
9808
  { method: "openConnection", class: "URL", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [] },
9777
9809
  { method: "openStream", class: "URL", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [] },
9778
- { method: "URL", class: "constructor", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
9779
- { method: "URI", class: "constructor", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
9810
+ // NOTE: URL/URI constructors removed constructing a URL object doesn't make a network
9811
+ // request in any language. The real SSRF sinks are openConnection/openStream/execute/etc.
9780
9812
  { method: "execute", class: "HttpClient", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
9781
9813
  { method: "send", class: "HttpClient", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
9782
9814
  { method: "getForObject", class: "RestTemplate", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
@@ -10253,6 +10285,17 @@ var DEFAULT_SANITIZERS = [
10253
10285
  { method: "encodeForHTML", removes: ["xss"] },
10254
10286
  { method: "escapeXml", removes: ["xss"] },
10255
10287
  { method: "htmlEscape", removes: ["xss"] },
10288
+ { method: "escapeHtml4", removes: ["xss"] },
10289
+ // Apache Commons StringEscapeUtils
10290
+ { method: "escapeHtml3", removes: ["xss"] },
10291
+ // Apache Commons StringEscapeUtils
10292
+ { method: "htmlSpecialChars", removes: ["xss"] },
10293
+ // PHP-style / common wrapper
10294
+ { method: "forHtml", class: "Encode", removes: ["xss"] },
10295
+ // OWASP Java Encoder
10296
+ { method: "forHtmlContent", class: "Encode", removes: ["xss"] },
10297
+ { method: "forHtmlAttribute", class: "Encode", removes: ["xss"] },
10298
+ { method: "forJavaScript", class: "Encode", removes: ["xss"] },
10256
10299
  { method: "encode_text", removes: ["xss"] },
10257
10300
  // Rust html_escape crate
10258
10301
  { method: "encode_safe", removes: ["xss"] },
@@ -10262,6 +10305,11 @@ var DEFAULT_SANITIZERS = [
10262
10305
  { method: "encodeForJavaScript", removes: ["xss"] },
10263
10306
  { method: "encodeForCSS", removes: ["xss"] },
10264
10307
  { method: "encodeForURL", removes: ["xss", "ssrf"] },
10308
+ // URL encoding wrapper aliases (common patterns in benchmarks and real-world code)
10309
+ { method: "encodeURL", removes: ["xss", "ssrf"] },
10310
+ { method: "urlEncode", removes: ["xss", "ssrf"] },
10311
+ { method: "escapeUrl", removes: ["xss", "ssrf"] },
10312
+ { method: "escapeURL", removes: ["xss", "ssrf"] },
10265
10313
  // Path Traversal
10266
10314
  { method: "normalize", class: "Path", removes: ["path_traversal"] },
10267
10315
  { method: "getCanonicalPath", class: "File", removes: ["path_traversal"] },
@@ -10379,11 +10427,11 @@ var DEFAULT_SANITIZERS = [
10379
10427
  { method: "canonicalize", removes: ["path_traversal"] },
10380
10428
  // Resolves symlinks, validates path exists
10381
10429
  // Rust Command Injection - allowlist validation
10382
- { method: "contains", removes: ["command_injection", "ssrf"] },
10430
+ { method: "contains", removes: ["command_injection", "ssrf", "open_redirect"] },
10383
10431
  // Used for allowlist checks
10384
- { method: "starts_with", removes: ["path_traversal", "ssrf"] },
10432
+ { method: "starts_with", removes: ["path_traversal", "ssrf", "open_redirect"] },
10385
10433
  // Path/URL prefix validation
10386
- { method: "ends_with", removes: ["path_traversal"] },
10434
+ { method: "ends_with", removes: ["path_traversal", "open_redirect"] },
10387
10435
  // Rust XSS - HTML escaping
10388
10436
  { method: "escape", class: "html_escape", removes: ["xss"] },
10389
10437
  { method: "encode_text", class: "html_escape", removes: ["xss"] },
@@ -10458,6 +10506,26 @@ function findSources(calls, types, patterns) {
10458
10506
  }
10459
10507
  }
10460
10508
  }
10509
+ const RUST_EXTRACTOR_TYPES = /^(?:Json|Form|Query|Path|Extension|Multipart)(?:<|$)|^(?:Body|Bytes)$/;
10510
+ for (const type of types) {
10511
+ for (const method of type.methods) {
10512
+ for (const param of method.parameters) {
10513
+ if (param.type && RUST_EXTRACTOR_TYPES.test(param.type)) {
10514
+ const paramLine = param.line ?? method.start_line;
10515
+ const alreadyExists = sources.some((s) => s.line === paramLine && s.type === "http_body");
10516
+ if (!alreadyExists) {
10517
+ sources.push({
10518
+ type: "http_body",
10519
+ location: `${param.type} ${param.name} in ${method.name}`,
10520
+ severity: "high",
10521
+ line: paramLine,
10522
+ confidence: 1
10523
+ });
10524
+ }
10525
+ }
10526
+ }
10527
+ }
10528
+ }
10461
10529
  for (const type of types) {
10462
10530
  for (const method of type.methods) {
10463
10531
  if (method.modifiers.includes("private")) continue;
@@ -10835,7 +10903,8 @@ function receiverMightBeClass(receiver, className) {
10835
10903
  "prepareStatement": ["PreparedStatement"],
10836
10904
  "getRuntime": ["Runtime"],
10837
10905
  "builder": ["Response", "ResponseBuilder", "HttpResponseBuilder"],
10838
- "stdin": ["stdin", "Stdin", "BufReader"]
10906
+ "stdin": ["stdin", "Stdin", "BufReader"],
10907
+ "lock": ["stdin", "Stdin", "StdinLock", "BufReader"]
10839
10908
  };
10840
10909
  const expectedTypes = returnTypeMappings[methodName];
10841
10910
  if (Array.isArray(expectedTypes) && expectedTypes.includes(className)) {
@@ -9155,6 +9155,7 @@ var DEFAULT_SOURCES = [
9155
9155
  { method: "lines", class: "BufReader", type: "file_input", severity: "medium", return_tainted: true },
9156
9156
  { method: "read_to_string", class: "stdin", type: "io_input", severity: "medium", return_tainted: true },
9157
9157
  { method: "read_line", class: "stdin", type: "io_input", severity: "medium", return_tainted: true },
9158
+ { method: "lines", class: "stdin", type: "io_input", severity: "medium", return_tainted: true },
9158
9159
  { method: "recv", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
9159
9160
  { method: "read", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
9160
9161
  { method: "read_to_end", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
@@ -9666,6 +9667,38 @@ var DEFAULT_SINKS = [
9666
9667
  { method: "processRequest", class: "Broker", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9667
9668
  // DolphinScheduler
9668
9669
  { method: "execute", class: "TaskExecuteThread", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9670
+ // Apache Commons JEXL (JEXL expression injection)
9671
+ { method: "createExpression", class: "JexlEngine", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9672
+ { method: "createScript", class: "JexlEngine", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9673
+ { method: "evaluate", class: "JexlExpression", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [] },
9674
+ { method: "execute", class: "JexlScript", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [] },
9675
+ // Janino expression evaluator (Calcite/Flink/Drill)
9676
+ { method: "createFastEvaluator", class: "ExpressionEvaluator", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9677
+ { method: "cook", class: "ExpressionEvaluator", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9678
+ { method: "cook", class: "ScriptEvaluator", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9679
+ { method: "cook", class: "ClassBodyEvaluator", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9680
+ { method: "cook", class: "SimpleCompiler", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9681
+ // Apache Camel Simple language (CVE-2018-8041 and similar)
9682
+ { method: "createExpression", class: "SimpleLanguage", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9683
+ { method: "createPredicate", class: "SimpleLanguage", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9684
+ // Thymeleaf StandardExpression (CVE-2023-38286 and similar)
9685
+ { method: "parseExpression", class: "StandardExpressionParser", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [1] },
9686
+ { method: "getValue", class: "StandardExpression", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [] },
9687
+ // FreeMarker direct template construction (CVE-2022-26336 and similar)
9688
+ { method: "Template", class: "Template", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [1] },
9689
+ // new Template(name, tainted)
9690
+ { method: "getTemplate", class: "Configuration", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0] },
9691
+ // Jinjava (Java Jinja template engine)
9692
+ { method: "render", class: "Jinjava", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0] },
9693
+ { method: "renderForResult", class: "Jinjava", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0] },
9694
+ // Spring Cloud Function RoutingFunction (CVE-2022-22963)
9695
+ { method: "getRequestedBeanName", class: "RoutingFunction", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [] },
9696
+ // Kotlin reflection (RCE via reflective construction)
9697
+ { method: "createInstance", class: "KClass", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [] },
9698
+ { method: "callBy", class: "KFunction", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0] },
9699
+ // Struts 2 deep injection (CVE-2017-5638 and descendants)
9700
+ { method: "translateVariables", class: "TextParseUtil", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9701
+ { method: "evaluate", class: "StrutsResultSupport", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
9669
9702
  // Deserialization (CWE-502)
9670
9703
  { method: "readObject", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [] },
9671
9704
  { method: "readUnshared", class: "ObjectInputStream", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [] },
@@ -9675,9 +9708,8 @@ var DEFAULT_SINKS = [
9675
9708
  { method: "load", class: "Yaml", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0] },
9676
9709
  { method: "loadAll", class: "Yaml", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0] },
9677
9710
  { method: "loadAs", class: "Yaml", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0] },
9678
- // JSON deserialization
9711
+ // JSON deserialization (Java FastJSON / Jackson — NOT JavaScript's safe JSON.parse)
9679
9712
  { method: "parseObject", class: "JSON", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0] },
9680
- { method: "parse", class: "JSON", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0] },
9681
9713
  { method: "parseObject", class: "JSONObject", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0] },
9682
9714
  { method: "fromJson", class: "Gson", type: "deserialization", cwe: "CWE-502", severity: "medium", arg_positions: [0] },
9683
9715
  // XMLDecoder
@@ -9710,8 +9742,8 @@ var DEFAULT_SINKS = [
9710
9742
  { method: "sendRedirect", type: "ssrf", cwe: "CWE-601", severity: "high", arg_positions: [0] },
9711
9743
  { method: "openConnection", class: "URL", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [] },
9712
9744
  { method: "openStream", class: "URL", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [] },
9713
- { method: "URL", class: "constructor", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
9714
- { method: "URI", class: "constructor", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
9745
+ // NOTE: URL/URI constructors removed constructing a URL object doesn't make a network
9746
+ // request in any language. The real SSRF sinks are openConnection/openStream/execute/etc.
9715
9747
  { method: "execute", class: "HttpClient", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
9716
9748
  { method: "send", class: "HttpClient", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
9717
9749
  { method: "getForObject", class: "RestTemplate", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
@@ -10188,6 +10220,17 @@ var DEFAULT_SANITIZERS = [
10188
10220
  { method: "encodeForHTML", removes: ["xss"] },
10189
10221
  { method: "escapeXml", removes: ["xss"] },
10190
10222
  { method: "htmlEscape", removes: ["xss"] },
10223
+ { method: "escapeHtml4", removes: ["xss"] },
10224
+ // Apache Commons StringEscapeUtils
10225
+ { method: "escapeHtml3", removes: ["xss"] },
10226
+ // Apache Commons StringEscapeUtils
10227
+ { method: "htmlSpecialChars", removes: ["xss"] },
10228
+ // PHP-style / common wrapper
10229
+ { method: "forHtml", class: "Encode", removes: ["xss"] },
10230
+ // OWASP Java Encoder
10231
+ { method: "forHtmlContent", class: "Encode", removes: ["xss"] },
10232
+ { method: "forHtmlAttribute", class: "Encode", removes: ["xss"] },
10233
+ { method: "forJavaScript", class: "Encode", removes: ["xss"] },
10191
10234
  { method: "encode_text", removes: ["xss"] },
10192
10235
  // Rust html_escape crate
10193
10236
  { method: "encode_safe", removes: ["xss"] },
@@ -10197,6 +10240,11 @@ var DEFAULT_SANITIZERS = [
10197
10240
  { method: "encodeForJavaScript", removes: ["xss"] },
10198
10241
  { method: "encodeForCSS", removes: ["xss"] },
10199
10242
  { method: "encodeForURL", removes: ["xss", "ssrf"] },
10243
+ // URL encoding wrapper aliases (common patterns in benchmarks and real-world code)
10244
+ { method: "encodeURL", removes: ["xss", "ssrf"] },
10245
+ { method: "urlEncode", removes: ["xss", "ssrf"] },
10246
+ { method: "escapeUrl", removes: ["xss", "ssrf"] },
10247
+ { method: "escapeURL", removes: ["xss", "ssrf"] },
10200
10248
  // Path Traversal
10201
10249
  { method: "normalize", class: "Path", removes: ["path_traversal"] },
10202
10250
  { method: "getCanonicalPath", class: "File", removes: ["path_traversal"] },
@@ -10314,11 +10362,11 @@ var DEFAULT_SANITIZERS = [
10314
10362
  { method: "canonicalize", removes: ["path_traversal"] },
10315
10363
  // Resolves symlinks, validates path exists
10316
10364
  // Rust Command Injection - allowlist validation
10317
- { method: "contains", removes: ["command_injection", "ssrf"] },
10365
+ { method: "contains", removes: ["command_injection", "ssrf", "open_redirect"] },
10318
10366
  // Used for allowlist checks
10319
- { method: "starts_with", removes: ["path_traversal", "ssrf"] },
10367
+ { method: "starts_with", removes: ["path_traversal", "ssrf", "open_redirect"] },
10320
10368
  // Path/URL prefix validation
10321
- { method: "ends_with", removes: ["path_traversal"] },
10369
+ { method: "ends_with", removes: ["path_traversal", "open_redirect"] },
10322
10370
  // Rust XSS - HTML escaping
10323
10371
  { method: "escape", class: "html_escape", removes: ["xss"] },
10324
10372
  { method: "encode_text", class: "html_escape", removes: ["xss"] },
@@ -10393,6 +10441,26 @@ function findSources(calls, types, patterns) {
10393
10441
  }
10394
10442
  }
10395
10443
  }
10444
+ const RUST_EXTRACTOR_TYPES = /^(?:Json|Form|Query|Path|Extension|Multipart)(?:<|$)|^(?:Body|Bytes)$/;
10445
+ for (const type of types) {
10446
+ for (const method of type.methods) {
10447
+ for (const param of method.parameters) {
10448
+ if (param.type && RUST_EXTRACTOR_TYPES.test(param.type)) {
10449
+ const paramLine = param.line ?? method.start_line;
10450
+ const alreadyExists = sources.some((s) => s.line === paramLine && s.type === "http_body");
10451
+ if (!alreadyExists) {
10452
+ sources.push({
10453
+ type: "http_body",
10454
+ location: `${param.type} ${param.name} in ${method.name}`,
10455
+ severity: "high",
10456
+ line: paramLine,
10457
+ confidence: 1
10458
+ });
10459
+ }
10460
+ }
10461
+ }
10462
+ }
10463
+ }
10396
10464
  for (const type of types) {
10397
10465
  for (const method of type.methods) {
10398
10466
  if (method.modifiers.includes("private")) continue;
@@ -10770,7 +10838,8 @@ function receiverMightBeClass(receiver, className) {
10770
10838
  "prepareStatement": ["PreparedStatement"],
10771
10839
  "getRuntime": ["Runtime"],
10772
10840
  "builder": ["Response", "ResponseBuilder", "HttpResponseBuilder"],
10773
- "stdin": ["stdin", "Stdin", "BufReader"]
10841
+ "stdin": ["stdin", "Stdin", "BufReader"],
10842
+ "lock": ["stdin", "Stdin", "StdinLock", "BufReader"]
10774
10843
  };
10775
10844
  const expectedTypes = returnTypeMappings[methodName];
10776
10845
  if (Array.isArray(expectedTypes) && expectedTypes.includes(className)) {
@@ -819,15 +819,8 @@ export class JavaScriptPlugin extends BaseLanguagePlugin {
819
819
  // =========================================================
820
820
  // Data Exposure Sinks (React Native)
821
821
  // =========================================================
822
- {
823
- // Logging sensitive data
824
- method: 'log',
825
- class: 'console',
826
- type: 'information_exposure',
827
- cwe: 'CWE-532',
828
- severity: 'low',
829
- argPositions: [0],
830
- },
822
+ // NOTE: console.log removed as a sink — too noisy for general-purpose analysis.
823
+ // console.log is ubiquitous and rarely a true vulnerability outside mobile contexts.
831
824
  {
832
825
  // Storing sensitive data insecurely
833
826
  method: 'setItem',