cognium-dev 4.9.21 → 4.9.22

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.
Files changed (2) hide show
  1. package/dist/cli.js +88 -19
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -24604,16 +24604,22 @@ class CSharpPlugin extends BaseLanguagePlugin {
24604
24604
  }
24605
24605
 
24606
24606
  // ../circle-ir/dist/languages/plugins/index.js
24607
+ function createBuiltinPlugins() {
24608
+ return [
24609
+ new JavaPlugin,
24610
+ new JavaScriptPlugin,
24611
+ new PythonPlugin,
24612
+ new RustPlugin,
24613
+ new BashPlugin,
24614
+ new HtmlPlugin,
24615
+ new VuePlugin,
24616
+ new GoPlugin,
24617
+ new CSharpPlugin
24618
+ ];
24619
+ }
24607
24620
  function registerBuiltinPlugins() {
24608
- registerLanguage(new JavaPlugin);
24609
- registerLanguage(new JavaScriptPlugin);
24610
- registerLanguage(new PythonPlugin);
24611
- registerLanguage(new RustPlugin);
24612
- registerLanguage(new BashPlugin);
24613
- registerLanguage(new HtmlPlugin);
24614
- registerLanguage(new VuePlugin);
24615
- registerLanguage(new GoPlugin);
24616
- registerLanguage(new CSharpPlugin);
24621
+ for (const plugin of createBuiltinPlugins())
24622
+ registerLanguage(plugin);
24617
24623
  }
24618
24624
  // ../circle-ir/dist/analysis/passes/cross-file-pass.js
24619
24625
  class CrossFilePass {
@@ -46991,6 +46997,8 @@ var JAVA_XML_OUTPUT_ONLY_RE = /\bnew\s+(?:DOMSource|StreamResult)\s*\(/;
46991
46997
  var JAVA_XML_PARSE_INPUT_RE = /\bnew\s+(?:StreamSource|SAXSource|InputSource)\s*\(/;
46992
46998
  var JAVA_DOC_BUILDER_NEW_DOCUMENT_RE = /\.\s*newDocument\s*\(\s*\)/;
46993
46999
  var JAVA_DOC_BUILDER_PARSE_RE = /(?:DocumentBuilder|builder)\s*\.\s*parse\s*\(/;
47000
+ var JAVA_HARDENING_SETTER_RE = /\.\s*(?:setFeature|setAttribute|setProperty|setXIncludeAware|setExpandEntityReferences)\s*\(/;
47001
+ var JAVA_FACTORY_CHAINED_RE = /\bnewInstance\s*\([^()]*\)\s*\.\s*(?:newDocumentBuilder|newSAXParser|newTransformer|newTemplates|newSchema|createXMLStreamReader|createXMLEventReader)\s*\(/;
46994
47002
  var PY_LXML_PARSER_INSECURE_DEFAULT_RE = /\bresolve_entities\s*=\s*False\b/;
46995
47003
 
46996
47004
  class XmlEntityExpansionPass {
@@ -47003,8 +47011,10 @@ class XmlEntityExpansionPass {
47003
47011
  const code = ctx.code ?? "";
47004
47012
  if (language === "java") {
47005
47013
  const safeInFile = JAVA_SAFE_EVIDENCE_RE.test(code);
47006
- if (safeInFile)
47007
- return { findings };
47014
+ const processWide = safeInFile && /jdk\.xml\./.test(code);
47015
+ const lines = safeInFile ? code.split(`
47016
+ `) : [];
47017
+ const methodRanges = safeInFile ? this.methodRanges(graph.ir.types) : [];
47008
47018
  const isXmlOutputOnly = JAVA_XML_OUTPUT_ONLY_RE.test(code) && !JAVA_XML_PARSE_INPUT_RE.test(code);
47009
47019
  const isDocumentBuilderEmptyOnly = JAVA_DOC_BUILDER_NEW_DOCUMENT_RE.test(code) && !JAVA_DOC_BUILDER_PARSE_RE.test(code);
47010
47020
  for (const call of graph.ir.calls) {
@@ -47016,6 +47026,8 @@ class XmlEntityExpansionPass {
47016
47026
  if (det.api === "DocumentBuilderFactory" && isDocumentBuilderEmptyOnly)
47017
47027
  continue;
47018
47028
  const line = call.location.line;
47029
+ if (safeInFile && (processWide || !this.isProvablyUnhardened(lines, line, methodRanges, det.api)))
47030
+ continue;
47019
47031
  findings.push({ line, language, ...det });
47020
47032
  ctx.addFinding({
47021
47033
  id: `${this.name}-${file}-${line}-${det.api}`,
@@ -47025,11 +47037,11 @@ class XmlEntityExpansionPass {
47025
47037
  cwe: det.cwe,
47026
47038
  severity: "high",
47027
47039
  level: "error",
47028
- message: `${det.api} created without disabling DTD / external-entity ` + "processing. Vulnerable to billion-laughs / quadratic " + "blow-up DoS (CWE-776) and external-entity disclosure " + '(CWE-611). Add `setFeature("http://apache.org/xml/features/' + 'disallow-doctype-decl", true)` (or the equivalent) before ' + "parsing.",
47040
+ message: `${det.api} created without disabling DTD / external-entity ` + "processing. Vulnerable to external-entity disclosure " + "(CWE-611) and billion-laughs / quadratic blow-up DoS " + '(CWE-776). Add `setFeature("http://apache.org/xml/features/' + 'disallow-doctype-decl", true)` (or the equivalent) before ' + "parsing.",
47029
47041
  file,
47030
47042
  line,
47031
47043
  fix: this.fixForJava(det.api),
47032
- evidence: { ...det, language, safeFeatureInFile: false }
47044
+ evidence: { ...det, language, safeFeatureInFile: safeInFile }
47033
47045
  });
47034
47046
  }
47035
47047
  return { findings };
@@ -47052,7 +47064,7 @@ class XmlEntityExpansionPass {
47052
47064
  cwe: det.cwe,
47053
47065
  severity: "high",
47054
47066
  level: "error",
47055
- message: `${det.api} called without an entity-safe parser. Vulnerable ` + "to billion-laughs / quadratic blow-up DoS (CWE-776) and " + "external-entity disclosure (CWE-611). Use `defusedxml` or pass " + "an `XMLParser(resolve_entities=False)` to lxml.",
47067
+ message: `${det.api} called without an entity-safe parser. Vulnerable ` + (det.cwe === "CWE-611" ? "to external-entity disclosure (CWE-611) and billion-laughs / " + "quadratic blow-up DoS (CWE-776). " : "to billion-laughs / quadratic blow-up DoS (CWE-776). ") + "Use `defusedxml` or pass " + "an `XMLParser(resolve_entities=False)` to lxml.",
47056
47068
  file,
47057
47069
  line,
47058
47070
  fix: this.fixForPython(det.api),
@@ -47063,6 +47075,63 @@ class XmlEntityExpansionPass {
47063
47075
  }
47064
47076
  return { findings };
47065
47077
  }
47078
+ methodRanges(types) {
47079
+ const out2 = [];
47080
+ for (const t of types ?? []) {
47081
+ for (const m of t.methods ?? []) {
47082
+ if (typeof m.start_line === "number" && typeof m.end_line === "number")
47083
+ out2.push([m.start_line, m.end_line]);
47084
+ }
47085
+ }
47086
+ return out2;
47087
+ }
47088
+ isProvablyUnhardened(lines, line, methodRanges, api) {
47089
+ let range = null;
47090
+ for (const r of methodRanges) {
47091
+ if (line < r[0] || line > r[1])
47092
+ continue;
47093
+ if (!range || r[1] - r[0] < range[1] - range[0])
47094
+ range = r;
47095
+ }
47096
+ if (!range)
47097
+ return false;
47098
+ let decl = "";
47099
+ let declEnd = line;
47100
+ for (;declEnd <= Math.min(line + 3, range[1]); declEnd++) {
47101
+ decl += " " + (lines[declEnd - 1] ?? "").trim();
47102
+ if (decl.includes(";"))
47103
+ break;
47104
+ }
47105
+ const body2 = lines.slice(line - 1, range[1]).join(`
47106
+ `);
47107
+ if (api === "TransformerFactory" && !/\bnew\s+StreamSource\s*\(/.test(body2))
47108
+ return false;
47109
+ if (JAVA_HARDENING_SETTER_RE.test(body2))
47110
+ return false;
47111
+ const chained = JAVA_FACTORY_CHAINED_RE.exec(decl);
47112
+ if (chained) {
47113
+ const prod = /[\w>\]]\s+([A-Za-z_$][\w$]*)\s*=/.exec(decl);
47114
+ if (!prod)
47115
+ return true;
47116
+ const pn = prod[1].replace(/\$/g, "\\$");
47117
+ const after = lines.slice(declEnd, range[1]).join(`
47118
+ `);
47119
+ return !new RegExp(`[(,]\\s*${pn}\\s*[,)]|\\breturn\\s+${pn}\\s*;`).test(after);
47120
+ }
47121
+ const m = /[\w>\]]\s+([A-Za-z_$][\w$]*)\s*=\s*[\w.]*\bnewInstance\s*\([^()]*\)\s*;/.exec(decl);
47122
+ if (!m)
47123
+ return false;
47124
+ const name2 = m[1].replace(/\$/g, "\\$");
47125
+ const rest = lines.slice(declEnd, range[1]).join(`
47126
+ `);
47127
+ const builds = new RegExp(`\\b${name2}\\s*\\.\\s*(?:newDocumentBuilder|newSAXParser|newTransformer|newTemplates|newSchema|createXMLStreamReader|createXMLEventReader)\\s*\\(`);
47128
+ if (!builds.test(rest))
47129
+ return false;
47130
+ const escapes = new RegExp(`[(,]\\s*${name2}\\s*[,)]|\\breturn\\s+${name2}\\s*;`);
47131
+ if (escapes.test(rest))
47132
+ return false;
47133
+ return true;
47134
+ }
47066
47135
  detectJavaCall(call) {
47067
47136
  if (call.method_name !== "newInstance")
47068
47137
  return null;
@@ -47073,7 +47142,7 @@ class XmlEntityExpansionPass {
47073
47142
  return {
47074
47143
  pattern: `${factory}.newInstance()`,
47075
47144
  api: factory,
47076
- cwe: "CWE-776"
47145
+ cwe: "CWE-611"
47077
47146
  };
47078
47147
  }
47079
47148
  }
@@ -47086,7 +47155,7 @@ class XmlEntityExpansionPass {
47086
47155
  return {
47087
47156
  pattern: `etree.${method}`,
47088
47157
  api: `lxml.etree.${method}`,
47089
- cwe: "CWE-776"
47158
+ cwe: "CWE-611"
47090
47159
  };
47091
47160
  }
47092
47161
  if ((method === "parse" || method === "fromstring") && (recv === "ET" || recv === "ElementTree" || recv.endsWith(".ElementTree"))) {
@@ -49777,7 +49846,7 @@ var colors = {
49777
49846
  };
49778
49847
 
49779
49848
  // src/version.ts
49780
- var version = "4.9.21";
49849
+ var version = "4.9.22";
49781
49850
 
49782
49851
  // src/formatters.ts
49783
49852
  var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
@@ -50322,8 +50391,8 @@ function generateSarifResults(results, crossFileData) {
50322
50391
 
50323
50392
  // src/build-info.ts
50324
50393
  var buildInfo = {
50325
- gitSha: "1ac1389",
50326
- builtAt: "2026-09-21T17:09:28.224Z"
50394
+ gitSha: "54a142d",
50395
+ builtAt: "2026-09-22T01:39:02.544Z"
50327
50396
  };
50328
50397
 
50329
50398
  // src/utils/args.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "4.9.21",
3
+ "version": "4.9.22",
4
4
  "description": "Static Application Security Testing CLI for detecting security vulnerabilities via taint tracking",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -67,7 +67,7 @@
67
67
  },
68
68
  "dependencies": {
69
69
  "@cognium/project-profile-detect": "1.1.1",
70
- "circle-ir": "4.9.21"
70
+ "circle-ir": "4.9.22"
71
71
  },
72
72
  "devDependencies": {
73
73
  "@types/node": "^26.6.1",