circle-ir 3.108.0 → 3.111.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.
- package/configs/sinks/nodejs.json +18 -0
- package/dist/analysis/config-loader.d.ts.map +1 -1
- package/dist/analysis/config-loader.js +38 -15
- package/dist/analysis/config-loader.js.map +1 -1
- package/dist/analysis/passes/sink-filter-pass.d.ts.map +1 -1
- package/dist/analysis/passes/sink-filter-pass.js +496 -0
- package/dist/analysis/passes/sink-filter-pass.js.map +1 -1
- package/dist/analysis/passes/taint-propagation-pass.d.ts.map +1 -1
- package/dist/analysis/passes/taint-propagation-pass.js +26 -2
- package/dist/analysis/passes/taint-propagation-pass.js.map +1 -1
- package/dist/analysis/taint-matcher.d.ts.map +1 -1
- package/dist/analysis/taint-matcher.js +145 -1
- package/dist/analysis/taint-matcher.js.map +1 -1
- package/dist/browser/circle-ir.js +472 -21
- package/dist/core/circle-ir-core.cjs +120 -16
- package/dist/core/circle-ir-core.js +120 -16
- package/package.json +1 -1
|
@@ -10551,10 +10551,20 @@ var DEFAULT_SINKS = [
|
|
|
10551
10551
|
{ method: "bash", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10552
10552
|
{ method: "shell", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10553
10553
|
{ method: "sh", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10554
|
-
|
|
10554
|
+
// cognium-dev #187 Sprint 54: arg_positions [0, 1] so the JS shell-mode shape
|
|
10555
|
+
// `spawn('sh', ['-c', tainted])` / `execFile('/bin/sh', ['-c', tainted])`
|
|
10556
|
+
// surfaces taint at the argv-array position (arg[1]).
|
|
10557
|
+
{ method: "spawn", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
|
|
10558
|
+
{ method: "spawnSync", languages: ["javascript", "typescript"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
|
|
10559
|
+
{ method: "execFile", languages: ["javascript", "typescript"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
|
|
10560
|
+
{ method: "execFileSync", languages: ["javascript", "typescript"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
|
|
10555
10561
|
{ method: "fork", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10556
10562
|
{ method: "popen", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10557
10563
|
{ method: "system", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10564
|
+
// execa (npm) — parses tainted shell-style strings into program+argv;
|
|
10565
|
+
// arg[0] is shell-injectable. cognium-dev #187 Sprint 54.
|
|
10566
|
+
{ method: "command", class: "execa", languages: ["javascript", "typescript"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10567
|
+
{ method: "commandSync", class: "execa", languages: ["javascript", "typescript"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10558
10568
|
// Apache Commons Exec
|
|
10559
10569
|
// Note: bare class 'Executor' removed (see comment above) — DefaultExecutor matched explicitly.
|
|
10560
10570
|
{ method: "setCommandline", class: "DefaultExecutor", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
@@ -11565,7 +11575,9 @@ var DEFAULT_SINKS = [
|
|
|
11565
11575
|
{ method: "aggregate", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "critical", arg_positions: [0] },
|
|
11566
11576
|
// pymongo dynamic attribute-access pattern: `db.users.find({...})` — receiver
|
|
11567
11577
|
// class isn't statically known. Method-only entries restricted to Python.
|
|
11568
|
-
// cognium-dev#104 Sprint 22
|
|
11578
|
+
// cognium-dev#104 Sprint 22, #194 Sprint 54 added `find`/`aggregate`.
|
|
11579
|
+
{ method: "find", type: "nosql_injection", cwe: "CWE-943", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
11580
|
+
{ method: "aggregate", type: "nosql_injection", cwe: "CWE-943", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
11569
11581
|
{ method: "find_one", type: "nosql_injection", cwe: "CWE-943", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
11570
11582
|
{ method: "update_one", type: "nosql_injection", cwe: "CWE-943", severity: "critical", arg_positions: [0, 1], languages: ["python"] },
|
|
11571
11583
|
{ method: "update_many", type: "nosql_injection", cwe: "CWE-943", severity: "critical", arg_positions: [0, 1], languages: ["python"] },
|
|
@@ -11577,21 +11589,32 @@ var DEFAULT_SINKS = [
|
|
|
11577
11589
|
{ method: "from_string", class: "Template", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
|
|
11578
11590
|
{ method: "Template", class: "jinja2", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
|
|
11579
11591
|
{ method: "Template", class: "mako", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
|
|
11580
|
-
// Python Log Injection
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
|
|
11592
|
+
// Python Log Injection — cognium-dev #193: positions [0, 1, 2, 3, 4]
|
|
11593
|
+
// cover both the format string (arg 0) and Python `logging`'s positional
|
|
11594
|
+
// *args (1..N), which get rendered into the log line via `%` substitution
|
|
11595
|
+
// (e.g. `log.warning("user=%s", user)` taints via arg 1). Five-arg cap
|
|
11596
|
+
// matches the established explicit-enumeration pattern used elsewhere in
|
|
11597
|
+
// this file.
|
|
11598
|
+
{ method: "info", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11599
|
+
{ method: "warning", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11600
|
+
{ method: "warn", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11601
|
+
{ method: "error", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11602
|
+
{ method: "debug", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11603
|
+
{ method: "critical", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11604
|
+
{ method: "fatal", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11605
|
+
{ method: "exception", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11606
|
+
{ method: "log", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [1, 2, 3, 4] },
|
|
11586
11607
|
// Python `logging` module top-level functions (e.g. logging.info(...))
|
|
11587
11608
|
// — cognium-dev#104 Sprint 22: OOP fixtures use `import logging; logging.info(self.msg)`.
|
|
11588
|
-
{ method: "info", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
|
|
11589
|
-
{ method: "warning", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
|
|
11590
|
-
{ method: "
|
|
11591
|
-
{ method: "
|
|
11592
|
-
{ method: "
|
|
11593
|
-
{ method: "
|
|
11594
|
-
{ method: "
|
|
11609
|
+
{ method: "info", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11610
|
+
{ method: "warning", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11611
|
+
{ method: "warn", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11612
|
+
{ method: "error", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11613
|
+
{ method: "debug", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11614
|
+
{ method: "critical", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11615
|
+
{ method: "fatal", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11616
|
+
{ method: "log", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [1, 2, 3, 4] },
|
|
11617
|
+
{ method: "exception", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11595
11618
|
// =========================================================================
|
|
11596
11619
|
// Java CWE-Bench Enhancement Patterns (Collection/Builder)
|
|
11597
11620
|
// =========================================================================
|
|
@@ -12134,10 +12157,50 @@ var PYTHON_TAINTED_PATTERNS = [
|
|
|
12134
12157
|
function analyzeTaint(calls, types, config = getDefaultConfig(), typeHierarchy, language, code) {
|
|
12135
12158
|
const sourceLines = code !== void 0 ? code.split("\n") : void 0;
|
|
12136
12159
|
const sources = findSources(calls, types, config.sources, sourceLines, language);
|
|
12137
|
-
const
|
|
12160
|
+
const sinkPatterns = expandPromisifyAliases(config.sinks, sourceLines, language);
|
|
12161
|
+
const sinks = findSinks(calls, sinkPatterns, typeHierarchy, language, sourceLines);
|
|
12138
12162
|
const sanitizers = findSanitizers(calls, types, config.sanitizers, sourceLines);
|
|
12139
12163
|
return { sources, sinks, sanitizers };
|
|
12140
12164
|
}
|
|
12165
|
+
function expandPromisifyAliases(patterns, sourceLines, language) {
|
|
12166
|
+
if (!sourceLines || sourceLines.length === 0) return patterns;
|
|
12167
|
+
if (language !== "javascript" && language !== "typescript") return patterns;
|
|
12168
|
+
const PROMISIFY_RE = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:util\s*\.\s*)?promisify\s*\(\s*([A-Za-z_$][\w$]*)\s*\)/;
|
|
12169
|
+
const innerToPattern = /* @__PURE__ */ new Map();
|
|
12170
|
+
for (const p of patterns) {
|
|
12171
|
+
if (p.languages && !p.languages.includes(language)) continue;
|
|
12172
|
+
if (p.class !== void 0) continue;
|
|
12173
|
+
if (!innerToPattern.has(p.method)) innerToPattern.set(p.method, p);
|
|
12174
|
+
}
|
|
12175
|
+
for (const p of patterns) {
|
|
12176
|
+
if (p.languages && !p.languages.includes(language)) continue;
|
|
12177
|
+
if (innerToPattern.has(p.method)) continue;
|
|
12178
|
+
innerToPattern.set(p.method, p);
|
|
12179
|
+
}
|
|
12180
|
+
const aliasPatterns = [];
|
|
12181
|
+
const seenAliases = /* @__PURE__ */ new Set();
|
|
12182
|
+
for (const line of sourceLines) {
|
|
12183
|
+
const m = PROMISIFY_RE.exec(line);
|
|
12184
|
+
if (!m) continue;
|
|
12185
|
+
const aliasName = m[1];
|
|
12186
|
+
const innerName = m[2];
|
|
12187
|
+
if (!aliasName || !innerName) continue;
|
|
12188
|
+
if (seenAliases.has(aliasName)) continue;
|
|
12189
|
+
const template = innerToPattern.get(innerName);
|
|
12190
|
+
if (!template) continue;
|
|
12191
|
+
seenAliases.add(aliasName);
|
|
12192
|
+
aliasPatterns.push({
|
|
12193
|
+
method: aliasName,
|
|
12194
|
+
type: template.type,
|
|
12195
|
+
cwe: template.cwe,
|
|
12196
|
+
severity: template.severity,
|
|
12197
|
+
arg_positions: template.arg_positions,
|
|
12198
|
+
languages: [language],
|
|
12199
|
+
note: `util.promisify alias of ${innerName} \u2014 cognium-dev #187`
|
|
12200
|
+
});
|
|
12201
|
+
}
|
|
12202
|
+
return aliasPatterns.length === 0 ? patterns : patterns.concat(aliasPatterns);
|
|
12203
|
+
}
|
|
12141
12204
|
function attachSourceLineCode(sources, sinks, code) {
|
|
12142
12205
|
const lines = code.split("\n");
|
|
12143
12206
|
for (const s of sources) {
|
|
@@ -12503,6 +12566,41 @@ function isSafeGoExecCommandCall(call, pattern, language) {
|
|
|
12503
12566
|
if (SHELL_PROGRAMS.has(program)) return false;
|
|
12504
12567
|
return true;
|
|
12505
12568
|
}
|
|
12569
|
+
function isSafeJSChildProcessCall(call, pattern, language) {
|
|
12570
|
+
if (language !== "javascript" && language !== "typescript") return false;
|
|
12571
|
+
if (pattern.type !== "command_injection") return false;
|
|
12572
|
+
const m = call.method_name;
|
|
12573
|
+
if (m !== "spawn" && m !== "spawnSync" && m !== "execFile" && m !== "execFileSync") return false;
|
|
12574
|
+
const programArg = call.arguments.find((a) => a.position === 0);
|
|
12575
|
+
if (!programArg) return false;
|
|
12576
|
+
let program;
|
|
12577
|
+
if (programArg.literal !== null && programArg.literal !== void 0) {
|
|
12578
|
+
program = String(programArg.literal).split("/").pop() ?? String(programArg.literal);
|
|
12579
|
+
} else {
|
|
12580
|
+
const expr = (programArg.expression ?? "").trim();
|
|
12581
|
+
if (!(expr.startsWith('"') || expr.startsWith("`") || expr.startsWith("'"))) {
|
|
12582
|
+
return false;
|
|
12583
|
+
}
|
|
12584
|
+
const stripped = expr.slice(1, -1);
|
|
12585
|
+
program = stripped.split("/").pop() ?? stripped;
|
|
12586
|
+
}
|
|
12587
|
+
const SHELL_PROGRAMS = /* @__PURE__ */ new Set([
|
|
12588
|
+
"sh",
|
|
12589
|
+
"bash",
|
|
12590
|
+
"zsh",
|
|
12591
|
+
"dash",
|
|
12592
|
+
"ash",
|
|
12593
|
+
"ksh",
|
|
12594
|
+
"cmd",
|
|
12595
|
+
"cmd.exe",
|
|
12596
|
+
"powershell",
|
|
12597
|
+
"pwsh",
|
|
12598
|
+
"powershell.exe",
|
|
12599
|
+
"pwsh.exe"
|
|
12600
|
+
]);
|
|
12601
|
+
if (SHELL_PROGRAMS.has(program)) return false;
|
|
12602
|
+
return true;
|
|
12603
|
+
}
|
|
12506
12604
|
function isSafeRustCommandCall(call, pattern, language) {
|
|
12507
12605
|
if (language !== "rust") return false;
|
|
12508
12606
|
if (pattern.type !== "command_injection") return false;
|
|
@@ -12717,6 +12815,9 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
|
|
|
12717
12815
|
if (isSafeRustCommandCall(call, pattern, language)) {
|
|
12718
12816
|
continue;
|
|
12719
12817
|
}
|
|
12818
|
+
if (isSafeJSChildProcessCall(call, pattern, language)) {
|
|
12819
|
+
continue;
|
|
12820
|
+
}
|
|
12720
12821
|
if (pattern.safe_if_class_literal_at !== void 0 && argIsClassLiteral(call, pattern.safe_if_class_literal_at)) {
|
|
12721
12822
|
continue;
|
|
12722
12823
|
}
|
|
@@ -13154,6 +13255,9 @@ function receiverMightBeClass(receiver, className) {
|
|
|
13154
13255
|
return true;
|
|
13155
13256
|
}
|
|
13156
13257
|
}
|
|
13258
|
+
if (className === "Logger" && /\.getLogger\(.*\)$/.test(receiver)) {
|
|
13259
|
+
return true;
|
|
13260
|
+
}
|
|
13157
13261
|
}
|
|
13158
13262
|
if (receiver.includes("::") && receiver.endsWith(")")) {
|
|
13159
13263
|
const scopedMatch = receiver.match(/^(\w+)::(\w+)\(.*\)$/);
|
|
@@ -10485,10 +10485,20 @@ var DEFAULT_SINKS = [
|
|
|
10485
10485
|
{ method: "bash", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10486
10486
|
{ method: "shell", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10487
10487
|
{ method: "sh", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10488
|
-
|
|
10488
|
+
// cognium-dev #187 Sprint 54: arg_positions [0, 1] so the JS shell-mode shape
|
|
10489
|
+
// `spawn('sh', ['-c', tainted])` / `execFile('/bin/sh', ['-c', tainted])`
|
|
10490
|
+
// surfaces taint at the argv-array position (arg[1]).
|
|
10491
|
+
{ method: "spawn", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
|
|
10492
|
+
{ method: "spawnSync", languages: ["javascript", "typescript"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
|
|
10493
|
+
{ method: "execFile", languages: ["javascript", "typescript"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
|
|
10494
|
+
{ method: "execFileSync", languages: ["javascript", "typescript"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
|
|
10489
10495
|
{ method: "fork", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10490
10496
|
{ method: "popen", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10491
10497
|
{ method: "system", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10498
|
+
// execa (npm) — parses tainted shell-style strings into program+argv;
|
|
10499
|
+
// arg[0] is shell-injectable. cognium-dev #187 Sprint 54.
|
|
10500
|
+
{ method: "command", class: "execa", languages: ["javascript", "typescript"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10501
|
+
{ method: "commandSync", class: "execa", languages: ["javascript", "typescript"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10492
10502
|
// Apache Commons Exec
|
|
10493
10503
|
// Note: bare class 'Executor' removed (see comment above) — DefaultExecutor matched explicitly.
|
|
10494
10504
|
{ method: "setCommandline", class: "DefaultExecutor", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
@@ -11499,7 +11509,9 @@ var DEFAULT_SINKS = [
|
|
|
11499
11509
|
{ method: "aggregate", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "critical", arg_positions: [0] },
|
|
11500
11510
|
// pymongo dynamic attribute-access pattern: `db.users.find({...})` — receiver
|
|
11501
11511
|
// class isn't statically known. Method-only entries restricted to Python.
|
|
11502
|
-
// cognium-dev#104 Sprint 22
|
|
11512
|
+
// cognium-dev#104 Sprint 22, #194 Sprint 54 added `find`/`aggregate`.
|
|
11513
|
+
{ method: "find", type: "nosql_injection", cwe: "CWE-943", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
11514
|
+
{ method: "aggregate", type: "nosql_injection", cwe: "CWE-943", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
11503
11515
|
{ method: "find_one", type: "nosql_injection", cwe: "CWE-943", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
11504
11516
|
{ method: "update_one", type: "nosql_injection", cwe: "CWE-943", severity: "critical", arg_positions: [0, 1], languages: ["python"] },
|
|
11505
11517
|
{ method: "update_many", type: "nosql_injection", cwe: "CWE-943", severity: "critical", arg_positions: [0, 1], languages: ["python"] },
|
|
@@ -11511,21 +11523,32 @@ var DEFAULT_SINKS = [
|
|
|
11511
11523
|
{ method: "from_string", class: "Template", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
|
|
11512
11524
|
{ method: "Template", class: "jinja2", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
|
|
11513
11525
|
{ method: "Template", class: "mako", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
|
|
11514
|
-
// Python Log Injection
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
|
|
11526
|
+
// Python Log Injection — cognium-dev #193: positions [0, 1, 2, 3, 4]
|
|
11527
|
+
// cover both the format string (arg 0) and Python `logging`'s positional
|
|
11528
|
+
// *args (1..N), which get rendered into the log line via `%` substitution
|
|
11529
|
+
// (e.g. `log.warning("user=%s", user)` taints via arg 1). Five-arg cap
|
|
11530
|
+
// matches the established explicit-enumeration pattern used elsewhere in
|
|
11531
|
+
// this file.
|
|
11532
|
+
{ method: "info", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11533
|
+
{ method: "warning", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11534
|
+
{ method: "warn", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11535
|
+
{ method: "error", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11536
|
+
{ method: "debug", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11537
|
+
{ method: "critical", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11538
|
+
{ method: "fatal", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11539
|
+
{ method: "exception", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11540
|
+
{ method: "log", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [1, 2, 3, 4] },
|
|
11520
11541
|
// Python `logging` module top-level functions (e.g. logging.info(...))
|
|
11521
11542
|
// — cognium-dev#104 Sprint 22: OOP fixtures use `import logging; logging.info(self.msg)`.
|
|
11522
|
-
{ method: "info", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
|
|
11523
|
-
{ method: "warning", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
|
|
11524
|
-
{ method: "
|
|
11525
|
-
{ method: "
|
|
11526
|
-
{ method: "
|
|
11527
|
-
{ method: "
|
|
11528
|
-
{ method: "
|
|
11543
|
+
{ method: "info", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11544
|
+
{ method: "warning", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11545
|
+
{ method: "warn", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11546
|
+
{ method: "error", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11547
|
+
{ method: "debug", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11548
|
+
{ method: "critical", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11549
|
+
{ method: "fatal", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11550
|
+
{ method: "log", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [1, 2, 3, 4] },
|
|
11551
|
+
{ method: "exception", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
11529
11552
|
// =========================================================================
|
|
11530
11553
|
// Java CWE-Bench Enhancement Patterns (Collection/Builder)
|
|
11531
11554
|
// =========================================================================
|
|
@@ -12068,10 +12091,50 @@ var PYTHON_TAINTED_PATTERNS = [
|
|
|
12068
12091
|
function analyzeTaint(calls, types, config = getDefaultConfig(), typeHierarchy, language, code) {
|
|
12069
12092
|
const sourceLines = code !== void 0 ? code.split("\n") : void 0;
|
|
12070
12093
|
const sources = findSources(calls, types, config.sources, sourceLines, language);
|
|
12071
|
-
const
|
|
12094
|
+
const sinkPatterns = expandPromisifyAliases(config.sinks, sourceLines, language);
|
|
12095
|
+
const sinks = findSinks(calls, sinkPatterns, typeHierarchy, language, sourceLines);
|
|
12072
12096
|
const sanitizers = findSanitizers(calls, types, config.sanitizers, sourceLines);
|
|
12073
12097
|
return { sources, sinks, sanitizers };
|
|
12074
12098
|
}
|
|
12099
|
+
function expandPromisifyAliases(patterns, sourceLines, language) {
|
|
12100
|
+
if (!sourceLines || sourceLines.length === 0) return patterns;
|
|
12101
|
+
if (language !== "javascript" && language !== "typescript") return patterns;
|
|
12102
|
+
const PROMISIFY_RE = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:util\s*\.\s*)?promisify\s*\(\s*([A-Za-z_$][\w$]*)\s*\)/;
|
|
12103
|
+
const innerToPattern = /* @__PURE__ */ new Map();
|
|
12104
|
+
for (const p of patterns) {
|
|
12105
|
+
if (p.languages && !p.languages.includes(language)) continue;
|
|
12106
|
+
if (p.class !== void 0) continue;
|
|
12107
|
+
if (!innerToPattern.has(p.method)) innerToPattern.set(p.method, p);
|
|
12108
|
+
}
|
|
12109
|
+
for (const p of patterns) {
|
|
12110
|
+
if (p.languages && !p.languages.includes(language)) continue;
|
|
12111
|
+
if (innerToPattern.has(p.method)) continue;
|
|
12112
|
+
innerToPattern.set(p.method, p);
|
|
12113
|
+
}
|
|
12114
|
+
const aliasPatterns = [];
|
|
12115
|
+
const seenAliases = /* @__PURE__ */ new Set();
|
|
12116
|
+
for (const line of sourceLines) {
|
|
12117
|
+
const m = PROMISIFY_RE.exec(line);
|
|
12118
|
+
if (!m) continue;
|
|
12119
|
+
const aliasName = m[1];
|
|
12120
|
+
const innerName = m[2];
|
|
12121
|
+
if (!aliasName || !innerName) continue;
|
|
12122
|
+
if (seenAliases.has(aliasName)) continue;
|
|
12123
|
+
const template = innerToPattern.get(innerName);
|
|
12124
|
+
if (!template) continue;
|
|
12125
|
+
seenAliases.add(aliasName);
|
|
12126
|
+
aliasPatterns.push({
|
|
12127
|
+
method: aliasName,
|
|
12128
|
+
type: template.type,
|
|
12129
|
+
cwe: template.cwe,
|
|
12130
|
+
severity: template.severity,
|
|
12131
|
+
arg_positions: template.arg_positions,
|
|
12132
|
+
languages: [language],
|
|
12133
|
+
note: `util.promisify alias of ${innerName} \u2014 cognium-dev #187`
|
|
12134
|
+
});
|
|
12135
|
+
}
|
|
12136
|
+
return aliasPatterns.length === 0 ? patterns : patterns.concat(aliasPatterns);
|
|
12137
|
+
}
|
|
12075
12138
|
function attachSourceLineCode(sources, sinks, code) {
|
|
12076
12139
|
const lines = code.split("\n");
|
|
12077
12140
|
for (const s of sources) {
|
|
@@ -12437,6 +12500,41 @@ function isSafeGoExecCommandCall(call, pattern, language) {
|
|
|
12437
12500
|
if (SHELL_PROGRAMS.has(program)) return false;
|
|
12438
12501
|
return true;
|
|
12439
12502
|
}
|
|
12503
|
+
function isSafeJSChildProcessCall(call, pattern, language) {
|
|
12504
|
+
if (language !== "javascript" && language !== "typescript") return false;
|
|
12505
|
+
if (pattern.type !== "command_injection") return false;
|
|
12506
|
+
const m = call.method_name;
|
|
12507
|
+
if (m !== "spawn" && m !== "spawnSync" && m !== "execFile" && m !== "execFileSync") return false;
|
|
12508
|
+
const programArg = call.arguments.find((a) => a.position === 0);
|
|
12509
|
+
if (!programArg) return false;
|
|
12510
|
+
let program;
|
|
12511
|
+
if (programArg.literal !== null && programArg.literal !== void 0) {
|
|
12512
|
+
program = String(programArg.literal).split("/").pop() ?? String(programArg.literal);
|
|
12513
|
+
} else {
|
|
12514
|
+
const expr = (programArg.expression ?? "").trim();
|
|
12515
|
+
if (!(expr.startsWith('"') || expr.startsWith("`") || expr.startsWith("'"))) {
|
|
12516
|
+
return false;
|
|
12517
|
+
}
|
|
12518
|
+
const stripped = expr.slice(1, -1);
|
|
12519
|
+
program = stripped.split("/").pop() ?? stripped;
|
|
12520
|
+
}
|
|
12521
|
+
const SHELL_PROGRAMS = /* @__PURE__ */ new Set([
|
|
12522
|
+
"sh",
|
|
12523
|
+
"bash",
|
|
12524
|
+
"zsh",
|
|
12525
|
+
"dash",
|
|
12526
|
+
"ash",
|
|
12527
|
+
"ksh",
|
|
12528
|
+
"cmd",
|
|
12529
|
+
"cmd.exe",
|
|
12530
|
+
"powershell",
|
|
12531
|
+
"pwsh",
|
|
12532
|
+
"powershell.exe",
|
|
12533
|
+
"pwsh.exe"
|
|
12534
|
+
]);
|
|
12535
|
+
if (SHELL_PROGRAMS.has(program)) return false;
|
|
12536
|
+
return true;
|
|
12537
|
+
}
|
|
12440
12538
|
function isSafeRustCommandCall(call, pattern, language) {
|
|
12441
12539
|
if (language !== "rust") return false;
|
|
12442
12540
|
if (pattern.type !== "command_injection") return false;
|
|
@@ -12651,6 +12749,9 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
|
|
|
12651
12749
|
if (isSafeRustCommandCall(call, pattern, language)) {
|
|
12652
12750
|
continue;
|
|
12653
12751
|
}
|
|
12752
|
+
if (isSafeJSChildProcessCall(call, pattern, language)) {
|
|
12753
|
+
continue;
|
|
12754
|
+
}
|
|
12654
12755
|
if (pattern.safe_if_class_literal_at !== void 0 && argIsClassLiteral(call, pattern.safe_if_class_literal_at)) {
|
|
12655
12756
|
continue;
|
|
12656
12757
|
}
|
|
@@ -13088,6 +13189,9 @@ function receiverMightBeClass(receiver, className) {
|
|
|
13088
13189
|
return true;
|
|
13089
13190
|
}
|
|
13090
13191
|
}
|
|
13192
|
+
if (className === "Logger" && /\.getLogger\(.*\)$/.test(receiver)) {
|
|
13193
|
+
return true;
|
|
13194
|
+
}
|
|
13091
13195
|
}
|
|
13092
13196
|
if (receiver.includes("::") && receiver.endsWith(")")) {
|
|
13093
13197
|
const scopedMatch = receiver.match(/^(\w+)::(\w+)\(.*\)$/);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "circle-ir",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.111.0",
|
|
4
4
|
"description": "High-performance Static Application Security Testing (SAST) library for detecting security vulnerabilities through taint analysis",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|