cognium-dev 3.179.0 → 3.181.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.
Files changed (2) hide show
  1. package/dist/cli.js +120 -4
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -10634,6 +10634,16 @@ var DEFAULT_SOURCES = [
10634
10634
  { method: "get", class: "Jedis", type: "db_input", severity: "medium", return_tainted: true, languages: ["java"] },
10635
10635
  { method: "hget", class: "Jedis", type: "db_input", severity: "medium", return_tainted: true, languages: ["java"] },
10636
10636
  { method: "mget", class: "Jedis", type: "db_input", severity: "medium", return_tainted: true, languages: ["java"] },
10637
+ { property: "body", object: "event", type: "http_body", severity: "high", property_tainted: true, languages: ["javascript", "typescript"] },
10638
+ { property: "queryStringParameters", object: "event", type: "http_query", severity: "high", property_tainted: true, languages: ["javascript", "typescript"] },
10639
+ { property: "multiValueQueryStringParameters", object: "event", type: "http_query", severity: "high", property_tainted: true, languages: ["javascript", "typescript"] },
10640
+ { property: "pathParameters", object: "event", type: "http_path", severity: "high", property_tainted: true, languages: ["javascript", "typescript"] },
10641
+ { property: "headers", object: "event", type: "http_header", severity: "high", property_tainted: true, languages: ["javascript", "typescript"] },
10642
+ { property: "multiValueHeaders", object: "event", type: "http_header", severity: "high", property_tainted: true, languages: ["javascript", "typescript"] },
10643
+ { property: "body", object: "event", type: "http_body", severity: "high", property_tainted: true, languages: ["python"] },
10644
+ { property: "queryStringParameters", object: "event", type: "http_query", severity: "high", property_tainted: true, languages: ["python"] },
10645
+ { property: "pathParameters", object: "event", type: "http_path", severity: "high", property_tainted: true, languages: ["python"] },
10646
+ { property: "headers", object: "event", type: "http_header", severity: "high", property_tainted: true, languages: ["python"] },
10637
10647
  { method: "decode", class: "jwt", type: "http_header", severity: "high", return_tainted: true, languages: ["python"] },
10638
10648
  { method: "get_unverified_claims", class: "jwt", type: "http_header", severity: "high", return_tainted: true, languages: ["python"] },
10639
10649
  { method: "get_unverified_header", class: "jwt", type: "http_header", severity: "high", return_tainted: true, languages: ["python"] },
@@ -24564,7 +24574,13 @@ var JS_TAINTED_PATTERNS = [
24564
24574
  { pattern: /\bdocument\.title\b/, type: "dom_input" },
24565
24575
  { pattern: /\bhistory\.state\b/, type: "dom_input" },
24566
24576
  { pattern: /\blocalStorage\.getItem\b/, type: "dom_input" },
24567
- { pattern: /\bsessionStorage\.getItem\b/, type: "dom_input" }
24577
+ { pattern: /\bsessionStorage\.getItem\b/, type: "dom_input" },
24578
+ { pattern: /\bevent\.body\b/, type: "http_body" },
24579
+ { pattern: /\bevent\.queryStringParameters\b/, type: "http_param" },
24580
+ { pattern: /\bevent\.multiValueQueryStringParameters\b/, type: "http_param" },
24581
+ { pattern: /\bevent\.pathParameters\b/, type: "http_path" },
24582
+ { pattern: /\bevent\.headers\b/, type: "http_header" },
24583
+ { pattern: /\bevent\.multiValueHeaders\b/, type: "http_header" }
24568
24584
  ];
24569
24585
  var PYTHON_TAINTED_PATTERNS2 = [
24570
24586
  { pattern: /\brequest\.args\b/, type: "http_param" },
@@ -29469,7 +29485,7 @@ function findPythonTaintedFormatStringFindings(code, file) {
29469
29485
  if (taintedVars.size === 0)
29470
29486
  return findings;
29471
29487
  const percentRe = /\b(\w+)\s*%\s*[\(\[\{"'\w]/;
29472
- const dotFormatRe = /\b(\w+)\s*\.\s*format\s*\(/;
29488
+ const dotFormatRe = /\b(\w+)\s*\.\s*(?:format|format_map)\s*\(/;
29473
29489
  const seen = new Set;
29474
29490
  for (let i2 = 0;i2 < lines.length; i2++) {
29475
29491
  const line = lines[i2];
@@ -32677,6 +32693,12 @@ function resolveFastjsonFromGradle(buildGradle) {
32677
32693
  const version2 = direct[1];
32678
32694
  return { version: version2, noneAutotype: /_noneautotype/i.test(version2) };
32679
32695
  }
32696
+ const constraintsBlockRe = /['"(]\s*com\.alibaba:fastjson\s*['")]\s*\)?\s*\{[\s\S]*?\bversion\s*\{[\s\S]*?\b(?:strictly|require|prefer)\s+['"]([^'"\s]+)['"]/;
32697
+ const constraintsBlock = buildGradle.match(constraintsBlockRe);
32698
+ if (constraintsBlock) {
32699
+ const version2 = constraintsBlock[1];
32700
+ return { version: version2, noneAutotype: /_noneautotype/i.test(version2) };
32701
+ }
32680
32702
  const propRefRe = /['"(]\s*com\.alibaba:fastjson:\$\{?([A-Za-z_][A-Za-z0-9_]*)\}?\s*['")]/;
32681
32703
  const propRef = buildGradle.match(propRefRe);
32682
32704
  if (!propRef)
@@ -32689,6 +32711,45 @@ function resolveFastjsonFromGradle(buildGradle) {
32689
32711
  const version = def[1];
32690
32712
  return { version, noneAutotype: /_noneautotype/i.test(version) };
32691
32713
  }
32714
+ function resolveFastjsonFromGradleCatalog(buildGradle, libsVersionsToml) {
32715
+ if (!buildGradle || !libsVersionsToml)
32716
+ return null;
32717
+ const librariesMatch = libsVersionsToml.match(/\[libraries\]([\s\S]*?)(?=\n\[|$)/);
32718
+ if (!librariesMatch)
32719
+ return null;
32720
+ const librariesBlock = librariesMatch[1];
32721
+ const moduleForm = librariesBlock.match(/^\s*([\w.-]+)\s*=\s*\{[^}]*\bmodule\s*=\s*"com\.alibaba:fastjson"[^}]*\}/m);
32722
+ const groupNameForm = librariesBlock.match(/^\s*([\w.-]+)\s*=\s*\{[^}]*\bgroup\s*=\s*"com\.alibaba"[^}]*\bname\s*=\s*"fastjson"[^}]*\}/m);
32723
+ const entry = moduleForm ?? groupNameForm;
32724
+ if (!entry)
32725
+ return null;
32726
+ const alias = entry[1];
32727
+ const entryBody = entry[0];
32728
+ const aliasEsc = alias.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
32729
+ const aliasRefRe = new RegExp(`\\blibs\\s*\\.\\s*${aliasEsc}\\b`);
32730
+ if (!aliasRefRe.test(buildGradle))
32731
+ return null;
32732
+ const inlineVersionM = entryBody.match(/\bversion\s*=\s*"([^"$][^"]*)"/);
32733
+ if (inlineVersionM) {
32734
+ const version2 = inlineVersionM[1];
32735
+ return { version: version2, noneAutotype: /_noneautotype/i.test(version2) };
32736
+ }
32737
+ const versionRefM = entryBody.match(/\bversion\.ref\s*=\s*"([^"]+)"/);
32738
+ if (!versionRefM)
32739
+ return null;
32740
+ const versionAlias = versionRefM[1];
32741
+ const versionsMatch = libsVersionsToml.match(/\[versions\]([\s\S]*?)(?=\n\[|$)/);
32742
+ if (!versionsMatch)
32743
+ return null;
32744
+ const versionsBlock = versionsMatch[1];
32745
+ const versionAliasEsc = versionAlias.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
32746
+ const versionLineRe = new RegExp(`^\\s*${versionAliasEsc}\\s*=\\s*"([^"]+)"`, "m");
32747
+ const versionLine = versionsBlock.match(versionLineRe);
32748
+ if (!versionLine)
32749
+ return null;
32750
+ const version = versionLine[1];
32751
+ return { version, noneAutotype: /_noneautotype/i.test(version) };
32752
+ }
32692
32753
  function resolvePyYamlFromRequirements(requirementsTxt) {
32693
32754
  if (!requirementsTxt)
32694
32755
  return null;
@@ -32798,7 +32859,8 @@ class DeserializationSafetyGatePass {
32798
32859
  const sinks = ctx.hasResult("sink-filter") ? ctx.getResult("sink-filter").sinks : graph.ir.taint.sinks;
32799
32860
  const pomXml = this.dependencyContext?.java?.pomXml;
32800
32861
  const buildGradle = this.dependencyContext?.java?.buildGradle;
32801
- const fastjson = (pomXml ? resolveFastjsonFromPom(pomXml) : null) ?? (buildGradle ? resolveFastjsonFromGradle(buildGradle) : null);
32862
+ const libsVersionsToml = this.dependencyContext?.java?.libsVersionsToml;
32863
+ const fastjson = (pomXml ? resolveFastjsonFromPom(pomXml) : null) ?? (buildGradle ? resolveFastjsonFromGradle(buildGradle) : null) ?? (buildGradle && libsVersionsToml ? resolveFastjsonFromGradleCatalog(buildGradle, libsVersionsToml) : null);
32802
32864
  const fastjsonHardened = fastjson?.noneAutotype === true && !fileReenablesFastjsonAutotype(code);
32803
32865
  const jacksonSafe = !fileEnablesJacksonPolymorphism(code);
32804
32866
  const snakeYamlSafe = fileConfiguresSnakeYamlSafely(code);
@@ -39735,6 +39797,58 @@ class ScanSecretsPass {
39735
39797
  }
39736
39798
  }
39737
39799
 
39800
+ // ../circle-ir/dist/analysis/passes/python-receiver-taint-format-pass.js
39801
+ class PythonReceiverTaintFormatPass {
39802
+ name = "python-receiver-taint-format";
39803
+ category = "security";
39804
+ run(ctx) {
39805
+ if (ctx.language !== "python") {
39806
+ return { findingsEmitted: 0 };
39807
+ }
39808
+ const { calls, meta, taint } = ctx.graph.ir;
39809
+ const taintedVarNames = new Set;
39810
+ for (const s of taint.sources) {
39811
+ if (typeof s.variable === "string" && s.variable.length > 0) {
39812
+ taintedVarNames.add(s.variable);
39813
+ }
39814
+ }
39815
+ if (taintedVarNames.size === 0) {
39816
+ return { findingsEmitted: 0 };
39817
+ }
39818
+ const seen = new Set;
39819
+ let count = 0;
39820
+ for (const call of calls) {
39821
+ if (call.method_name !== "format" && call.method_name !== "format_map")
39822
+ continue;
39823
+ const receiver = call.receiver;
39824
+ if (!receiver)
39825
+ continue;
39826
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(receiver))
39827
+ continue;
39828
+ if (!taintedVarNames.has(receiver))
39829
+ continue;
39830
+ const seenKey = `${call.location.line}:${receiver}`;
39831
+ if (seen.has(seenKey))
39832
+ continue;
39833
+ seen.add(seenKey);
39834
+ ctx.addFinding({
39835
+ id: `format_string-${meta.file}-${call.location.line}-${receiver}-${call.method_name}`,
39836
+ pass: this.name,
39837
+ category: "security",
39838
+ rule_id: "format_string",
39839
+ cwe: "CWE-134",
39840
+ severity: "medium",
39841
+ level: "warning",
39842
+ message: `Format-string vulnerability: the format template \`${receiver}\` ` + `is tainted (traces back to a taint source) and used as the ` + `receiver of \`${call.method_name}(...)\`. Attacker can leak ` + `object attributes via \`{obj.__class__.__mro__[…]}\` chains or ` + `crash the process via unbounded specifiers. Use a literal ` + `format string and pass user input as an argument instead.`,
39843
+ file: meta.file,
39844
+ line: call.location.line
39845
+ });
39846
+ count++;
39847
+ }
39848
+ return { findingsEmitted: count };
39849
+ }
39850
+ }
39851
+
39738
39852
  // ../circle-ir/dist/analysis/passes/spring4shell-pass.js
39739
39853
  var CONTROLLER_ANNOTATIONS = new Set([
39740
39854
  "Controller",
@@ -44406,6 +44520,8 @@ async function analyze(code, filePath, language, options = {}) {
44406
44520
  pipeline.add(new LibraryProfileCwe22PathGatePass);
44407
44521
  if (!disabledPasses.has("scan-secrets"))
44408
44522
  pipeline.add(new ScanSecretsPass);
44523
+ if (!disabledPasses.has("python-receiver-taint-format"))
44524
+ pipeline.add(new PythonReceiverTaintFormatPass);
44409
44525
  if (!disabledPasses.has("dead-code"))
44410
44526
  pipeline.add(new DeadCodePass);
44411
44527
  if (!disabledPasses.has("missing-await"))
@@ -45335,7 +45451,7 @@ var colors = {
45335
45451
  };
45336
45452
 
45337
45453
  // src/version.ts
45338
- var version = "3.179.0";
45454
+ var version = "3.181.0";
45339
45455
 
45340
45456
  // src/formatters.ts
45341
45457
  var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "3.179.0",
3
+ "version": "3.181.0",
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",
@@ -66,7 +66,7 @@
66
66
  },
67
67
  "dependencies": {
68
68
  "@cognium/project-profile-detect": "^1.1.0",
69
- "circle-ir": "^3.179.0"
69
+ "circle-ir": "^3.181.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",