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.
- package/dist/analysis/config-loader.js +50 -7
- package/dist/analysis/config-loader.js.map +1 -1
- package/dist/analysis/passes/language-sources-pass.js +7 -0
- package/dist/analysis/passes/language-sources-pass.js.map +1 -1
- package/dist/analysis/passes/sink-filter-pass.d.ts +1 -1
- package/dist/analysis/passes/sink-filter-pass.js +19 -4
- package/dist/analysis/passes/sink-filter-pass.js.map +1 -1
- package/dist/analysis/taint-matcher.js +23 -0
- package/dist/analysis/taint-matcher.js.map +1 -1
- package/dist/browser/circle-ir.js +101 -21
- package/dist/core/circle-ir-core.cjs +77 -8
- package/dist/core/circle-ir-core.js +77 -8
- package/dist/languages/plugins/javascript.js +2 -9
- package/dist/languages/plugins/javascript.js.map +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
9666
|
-
|
|
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
|
-
|
|
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
|
-
|
|
9779
|
-
|
|
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
|
-
|
|
9714
|
-
|
|
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
|
-
|
|
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',
|