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.
@@ -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
- { method: "spawn", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
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
- { method: "info", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11582
- { method: "warning", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11583
- { method: "error", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11584
- { method: "debug", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11585
- { method: "critical", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
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: "error", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11591
- { method: "debug", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11592
- { method: "critical", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11593
- { method: "log", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [1] },
11594
- { method: "exception", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
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 sinks = findSinks(calls, config.sinks, typeHierarchy, language, sourceLines);
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
- { method: "spawn", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
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
- { method: "info", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11516
- { method: "warning", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11517
- { method: "error", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11518
- { method: "debug", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11519
- { method: "critical", class: "logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
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: "error", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11525
- { method: "debug", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11526
- { method: "critical", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
11527
- { method: "log", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [1] },
11528
- { method: "exception", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0] },
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 sinks = findSinks(calls, config.sinks, typeHierarchy, language, sourceLines);
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.108.0",
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",