cognium-dev 3.103.0 → 3.105.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 +328 -11
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -18060,6 +18060,18 @@ function isHighConfidence(finding) {
18060
18060
  return finding.confidence === undefined || finding.confidence === "high";
18061
18061
  }
18062
18062
 
18063
+ // ../circle-ir/dist/analysis/library-api-surface-downgrade.js
18064
+ var LIBRARY_API_SURFACE_TAG = "library-api-surface:caller-responsibility";
18065
+ function applyLibraryApiSurfaceDowngrade(findings) {
18066
+ return findings.map((f) => {
18067
+ if (!f.tags?.includes(LIBRARY_API_SURFACE_TAG))
18068
+ return f;
18069
+ if (f.severity === "medium" || f.severity === "low")
18070
+ return f;
18071
+ return { ...f, severity: "medium", level: "warning" };
18072
+ });
18073
+ }
18074
+
18063
18075
  // ../circle-ir/dist/languages/registry.js
18064
18076
  class DefaultLanguageRegistry {
18065
18077
  plugins = new Map;
@@ -23545,6 +23557,39 @@ var PROTOCOL_CLIENT_PACKAGES = [
23545
23557
  var OS_EXEC_RECEIVER_RE = /\b(?:Runtime|ProcessBuilder|DefaultExecutor|Executor|Exec|Launcher|ProcStarter|ProcessExecutor|RuntimeUtil)\s*[.(]/;
23546
23558
  var PROCESS_BUILDER_ARGV_FORM_RE = /\bnew\s+ProcessBuilder\s*\(\s*(?:Arrays\.asList\b|List\.of\b|Collections\.singletonList\b|new\s+ArrayList\b|new\s+String\s*\[\s*\]\s*\{|"[^"]*"\s*,)/;
23547
23559
  var JAVA_THROW_STATEMENT_RE = /^\s*throw\s+new\s+\w+(?:Exception|Error)\b/;
23560
+ var JEXL_ENGINE_TYPES = new Set(["JexlEngine", "Jexl", "JxltEngine"]);
23561
+ var JEXL_EXPRESSION_TYPE_RE = /(?:Jexl)?(?:Expression|Script|Template)(?:Script)?$/;
23562
+ var TEMPLATE_COMPILE_RECEIVER_TYPES = new Set([
23563
+ "Handlebars",
23564
+ "Mustache",
23565
+ "MustacheFactory",
23566
+ "DefaultMustacheFactory",
23567
+ "Pebble",
23568
+ "PebbleEngine",
23569
+ "PebbleEngineBuilder",
23570
+ "VelocityEngine",
23571
+ "Velocity",
23572
+ "Configuration",
23573
+ "Freemarker",
23574
+ "FreeMarker",
23575
+ "TemplateEngine",
23576
+ "SpringTemplateEngine",
23577
+ "Thymeleaf"
23578
+ ]);
23579
+ var SPI_GET_RESOURCES_RE = /\.getResources\s*\(\s*["'][^"']*META-INF\/services\/[^"']*["']\s*\)/;
23580
+ var CLASSLOADER_PARENT_TYPES = new Set([
23581
+ "ClassLoader",
23582
+ "URLClassLoader",
23583
+ "SecureClassLoader"
23584
+ ]);
23585
+ var CLASSLOADER_NAME_RE = /(?:CachingProvider|ClassLoader|SpiLoader)$/;
23586
+ var LOADCLASS_OVERRIDE_METHOD_RE = /\b(?:public|protected)\s+(?:[\w<>?,\s]+\s+)?(?:loadClass|findClass)\s*\(\s*String\b/;
23587
+ var JAVA_CLASS_DECL_RE = /\bclass\s+([A-Z]\w*)\b(?:\s+extends\s+([A-Z][\w.]*))?(?:\s+implements\s+([A-Z][\w.,<>\s?]*))?/;
23588
+ var SQL_BUILDER_CLASS_RE = /(?:Dialect|SqlBuilder|Quoter|Wrapper|SqlGenerator|QueryBuilder)$/;
23589
+ var SQL_BUILDER_WRAPPER_CALL_RE = /\.(?:wrap|quote|escape|identifier)\s*\(/;
23590
+ var SQL_EXTRACTION_RETURN_RE = /^(?:String|CharSequence|Optional\s*<\s*String\s*>)$/;
23591
+ var SQL_EXTRACTION_NAME_RE = /^(?:get|extract|build).*(?:[Ss]ql|[Qq]uery)|^toSql|.*Statement.*ToString$|.*Query.*String$/;
23592
+ var SQL_EXTRACTION_PRIMITIVE_INPUT_RE = /^(?:String|CharSequence)$/;
23548
23593
  function resolveJavaReceiverType(receiver, sinkLine, sourceLines) {
23549
23594
  if (!receiver || !/^[A-Za-z_]\w*$/.test(receiver))
23550
23595
  return null;
@@ -23561,6 +23606,48 @@ function resolveJavaReceiverType(receiver, sinkLine, sourceLines) {
23561
23606
  }
23562
23607
  return null;
23563
23608
  }
23609
+ function findEnclosingClassDecl(sinkLine, sourceLines) {
23610
+ const end = Math.min(sourceLines.length, sinkLine);
23611
+ for (let i2 = end - 1;i2 >= 0; i2--) {
23612
+ const ln = sourceLines[i2] ?? "";
23613
+ const m = ln.match(JAVA_CLASS_DECL_RE);
23614
+ if (!m)
23615
+ continue;
23616
+ const implementsTypes = m[3] ? m[3].split(",").map((s) => s.replace(/<[^>]*>/g, "").trim()).filter(Boolean).map((s) => {
23617
+ const parts2 = s.split(".");
23618
+ return parts2[parts2.length - 1] ?? s;
23619
+ }) : [];
23620
+ const extendsRaw = m[2] ?? null;
23621
+ const extendsType = extendsRaw ? (() => {
23622
+ const p = extendsRaw.split(".");
23623
+ return p[p.length - 1] ?? extendsRaw;
23624
+ })() : null;
23625
+ return { name: m[1], extendsType, implementsTypes };
23626
+ }
23627
+ return null;
23628
+ }
23629
+ function isInsideLoadClassOverride(sinkLine, sourceLines) {
23630
+ const limit = Math.max(0, sinkLine - 200);
23631
+ for (let i2 = sinkLine - 2;i2 >= limit; i2--) {
23632
+ const ln = sourceLines[i2] ?? "";
23633
+ if (LOADCLASS_OVERRIDE_METHOD_RE.test(ln))
23634
+ return true;
23635
+ if (/\bclass\s+[A-Z]\w*\b/.test(ln))
23636
+ return false;
23637
+ }
23638
+ return false;
23639
+ }
23640
+ function findEnclosingMethodFromIr(types, sinkLine) {
23641
+ for (const t of types) {
23642
+ if (sinkLine < t.start_line || sinkLine > t.end_line)
23643
+ continue;
23644
+ for (const m of t.methods) {
23645
+ if (sinkLine >= m.start_line && sinkLine <= m.end_line)
23646
+ return m;
23647
+ }
23648
+ }
23649
+ return null;
23650
+ }
23564
23651
  function isJavaLiteralOrAnnotationAccessor(expr) {
23565
23652
  const e = expr.trim();
23566
23653
  if (e === "")
@@ -23842,6 +23929,168 @@ class SinkFilterPass {
23842
23929
  return true;
23843
23930
  });
23844
23931
  }
23932
+ if (language === "java") {
23933
+ const sourceLines = ctx.code.split(`
23934
+ `);
23935
+ for (const sink of filtered) {
23936
+ if (sink.type !== "code_injection")
23937
+ continue;
23938
+ const sinkLineText = sourceLines[sink.line - 1] ?? "";
23939
+ const receiverMatch = sinkLineText.match(/\b(\w+)\s*\.\s*(\w+)\s*\(/);
23940
+ const receiver = receiverMatch?.[1];
23941
+ const method = sink.method ?? receiverMatch?.[2];
23942
+ let shouldTag = false;
23943
+ if (method === "createExpression" && receiver) {
23944
+ const recvType = resolveJavaReceiverType(receiver, sink.line, sourceLines);
23945
+ if (recvType && JEXL_ENGINE_TYPES.has(recvType))
23946
+ shouldTag = true;
23947
+ }
23948
+ if (!shouldTag && method === "evaluate" && receiver) {
23949
+ const recvType = resolveJavaReceiverType(receiver, sink.line, sourceLines);
23950
+ if (recvType && JEXL_EXPRESSION_TYPE_RE.test(recvType))
23951
+ shouldTag = true;
23952
+ }
23953
+ if (!shouldTag && method === "compile" && receiver) {
23954
+ const recvType = resolveJavaReceiverType(receiver, sink.line, sourceLines);
23955
+ if (recvType && TEMPLATE_COMPILE_RECEIVER_TYPES.has(recvType))
23956
+ shouldTag = true;
23957
+ }
23958
+ if (!shouldTag && method === "forName") {
23959
+ const start2 = Math.max(0, sink.line - 31);
23960
+ const end = Math.min(sourceLines.length, sink.line + 30);
23961
+ for (let i2 = start2;i2 < end; i2++) {
23962
+ if (SPI_GET_RESOURCES_RE.test(sourceLines[i2] ?? "")) {
23963
+ shouldTag = true;
23964
+ break;
23965
+ }
23966
+ }
23967
+ }
23968
+ if (!shouldTag && method && (method === "loadClass" || method === "findClass" || method === "forName")) {
23969
+ const enclosing = findEnclosingClassDecl(sink.line, sourceLines);
23970
+ if (enclosing) {
23971
+ const extendsClassLoader = enclosing.extendsType !== null && CLASSLOADER_PARENT_TYPES.has(enclosing.extendsType);
23972
+ const implementsSpi = enclosing.implementsTypes.some((t) => /CachingProvider$/.test(t));
23973
+ const nameLooksLikeLoader = CLASSLOADER_NAME_RE.test(enclosing.name);
23974
+ if (extendsClassLoader || implementsSpi || nameLooksLikeLoader)
23975
+ shouldTag = true;
23976
+ }
23977
+ if (!shouldTag && isInsideLoadClassOverride(sink.line, sourceLines)) {
23978
+ shouldTag = true;
23979
+ }
23980
+ }
23981
+ if (shouldTag) {
23982
+ const existing = sink.tags ?? [];
23983
+ if (!existing.includes(LIBRARY_API_SURFACE_TAG)) {
23984
+ sink.tags = [...existing, LIBRARY_API_SURFACE_TAG];
23985
+ }
23986
+ }
23987
+ }
23988
+ }
23989
+ if (language === "java") {
23990
+ const sourceLines = ctx.code.split(`
23991
+ `);
23992
+ filtered = filtered.filter((sink) => {
23993
+ if (sink.type !== "code_injection")
23994
+ return true;
23995
+ const sinkLineText = sourceLines[sink.line - 1] ?? "";
23996
+ const receiverMatch = sinkLineText.match(/\b(\w+)\s*\.\s*(\w+)\s*\(/);
23997
+ const receiver = receiverMatch?.[1];
23998
+ if (!receiver)
23999
+ return true;
24000
+ const start2 = Math.max(0, sink.line - 200);
24001
+ let arrayName = null;
24002
+ const foreachRe = new RegExp(`\\bfor\\s*\\(\\s*\\w[\\w<>?]*\\s+${receiver}\\s*:\\s*(\\w+)\\b`);
24003
+ for (let i2 = sink.line - 1;i2 >= start2; i2--) {
24004
+ const ln = sourceLines[i2] ?? "";
24005
+ const fm = ln.match(foreachRe);
24006
+ if (fm) {
24007
+ arrayName = fm[1];
24008
+ break;
24009
+ }
24010
+ }
24011
+ if (!arrayName) {
24012
+ const methodNameMatch = sinkLineText.match(/\.(\w+)\s*\(/);
24013
+ const methodNameRe = methodNameMatch ? methodNameMatch[1] : "\\w+";
24014
+ const idxRe = new RegExp(`\\b(\\w+)\\s*\\[[^\\]]+\\]\\s*\\.\\s*${methodNameRe}\\s*\\(`);
24015
+ const im = sinkLineText.match(idxRe);
24016
+ if (im)
24017
+ arrayName = im[1];
24018
+ }
24019
+ if (!arrayName)
24020
+ return true;
24021
+ const declRe = new RegExp(`\\bprivate\\s+static\\s+final\\s+(?:[\\w<>?,\\s]+)\\[\\s*\\]\\s+${arrayName}\\s*=`);
24022
+ let declStart = -1;
24023
+ for (let i2 = 0;i2 < sink.line; i2++) {
24024
+ if (declRe.test(sourceLines[i2] ?? "")) {
24025
+ declStart = i2;
24026
+ break;
24027
+ }
24028
+ }
24029
+ if (declStart < 0)
24030
+ return true;
24031
+ let body2 = "";
24032
+ for (let i2 = declStart;i2 < Math.min(sourceLines.length, declStart + 40); i2++) {
24033
+ body2 += (sourceLines[i2] ?? "") + `
24034
+ `;
24035
+ if (/\}\s*;/.test(sourceLines[i2] ?? ""))
24036
+ break;
24037
+ }
24038
+ const initMatch = body2.match(/=\s*(?:new\s+[\w<>?,\s]+\[\s*\]\s*)?\{([\s\S]*?)\}\s*;/);
24039
+ if (!initMatch)
24040
+ return true;
24041
+ const elements = initMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
24042
+ if (elements.length === 0)
24043
+ return true;
24044
+ const allNewLiterals = elements.every((e) => /^new\s+[A-Z]\w*\s*\([^)]*\)$/.test(e));
24045
+ if (allNewLiterals)
24046
+ return false;
24047
+ return true;
24048
+ });
24049
+ }
24050
+ if (language === "java") {
24051
+ const sourceLines = ctx.code.split(`
24052
+ `);
24053
+ filtered = filtered.filter((sink) => {
24054
+ if (sink.type !== "sql_injection")
24055
+ return true;
24056
+ const enclosing = findEnclosingClassDecl(sink.line, sourceLines);
24057
+ if (!enclosing)
24058
+ return true;
24059
+ if (!SQL_BUILDER_CLASS_RE.test(enclosing.name))
24060
+ return true;
24061
+ const lo = Math.max(0, sink.line - 11);
24062
+ const hi = Math.min(sourceLines.length, sink.line + 10);
24063
+ for (let i2 = lo;i2 < hi; i2++) {
24064
+ if (SQL_BUILDER_WRAPPER_CALL_RE.test(sourceLines[i2] ?? ""))
24065
+ return false;
24066
+ }
24067
+ return true;
24068
+ });
24069
+ }
24070
+ if (language === "java") {
24071
+ const types = graph.ir.types ?? [];
24072
+ if (types.length > 0) {
24073
+ filtered = filtered.filter((sink) => {
24074
+ if (sink.type !== "sql_injection")
24075
+ return true;
24076
+ const enclosing = findEnclosingMethodFromIr(types, sink.line);
24077
+ if (!enclosing)
24078
+ return true;
24079
+ const ret = (enclosing.return_type ?? "").replace(/\s+/g, " ").trim();
24080
+ if (!SQL_EXTRACTION_RETURN_RE.test(ret))
24081
+ return true;
24082
+ if (!SQL_EXTRACTION_NAME_RE.test(enclosing.name))
24083
+ return true;
24084
+ const firstParamType = enclosing.parameters[0]?.type ?? null;
24085
+ if (firstParamType === null)
24086
+ return true;
24087
+ const simpleType = firstParamType.replace(/<[^>]*>/g, "").trim();
24088
+ if (SQL_EXTRACTION_PRIMITIVE_INPUT_RE.test(simpleType))
24089
+ return true;
24090
+ return false;
24091
+ });
24092
+ }
24093
+ }
23845
24094
  return { sources, sinks: filtered, sanitizers };
23846
24095
  }
23847
24096
  }
@@ -29903,6 +30152,33 @@ function mapReturnValueToCorsRule(returnValue) {
29903
30152
  };
29904
30153
  }
29905
30154
 
30155
+ // ../circle-ir/dist/analysis/passes/_fp-allowlists.js
30156
+ var PEM_BODY_RE = /[A-Za-z0-9+/]{30,}/;
30157
+ function pemHasInlineBody(lines, hitLineIdx) {
30158
+ const end = Math.min(hitLineIdx + 5, lines.length);
30159
+ for (let l = hitLineIdx;l < end; l++) {
30160
+ if (PEM_BODY_RE.test(lines[l] ?? ""))
30161
+ return true;
30162
+ }
30163
+ return false;
30164
+ }
30165
+ var CLI_OPTION_KEY_RE = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)+$/;
30166
+ function isCliOptionKeyValue(value) {
30167
+ return value.length <= 48 && CLI_OPTION_KEY_RE.test(value);
30168
+ }
30169
+ var PROTOCOL_MANDATED_PATH_RE = /(?:^|[\\/])(?:ntlm|kerberos|krb5|smb1?|sasl[\\/]cram-md5?|digest)(?:[\\/]|$)/i;
30170
+ var PROTOCOL_MANDATED_CLASS_RE = /\b(?:N[Tt][Ll][Mm](?:Scheme|Engine|AuthHandler|AuthScheme)|Krb5\w+|KerberosClient|Smb\w*Signing|CramMd5\w*|DigestScheme)\b/;
30171
+ var PROTOCOL_MANDATED_CITATION_RE = /\b(?:MS-NLMP|RFC\s*4757|RFC\s*3961|RFC\s*2617|RFC\s*2195|CRAM-MD5)\b/i;
30172
+ function isProtocolMandatedCryptoFile(file, code) {
30173
+ if (PROTOCOL_MANDATED_PATH_RE.test(file))
30174
+ return true;
30175
+ if (PROTOCOL_MANDATED_CLASS_RE.test(code))
30176
+ return true;
30177
+ if (PROTOCOL_MANDATED_CITATION_RE.test(code))
30178
+ return true;
30179
+ return false;
30180
+ }
30181
+
29906
30182
  // ../circle-ir/dist/analysis/passes/scan-secrets-pass.js
29907
30183
  var TEST_PATH_RE3 = /(?:^|[\\/])(?:test|tests|spec|specs|__tests?__|__mocks?__|fixtures?|testdata)(?:[\\/]|$)/i;
29908
30184
  var TEST_FILENAME_RE = /(?:\.(?:test|spec)\.[cm]?[jt]sx?|_test\.go|_test\.py|Test\.java|Tests\.java)$/i;
@@ -30069,6 +30345,8 @@ function isLikelyCredentialAssignment(line) {
30069
30345
  return null;
30070
30346
  if (/^[0-9]+$/.test(value) && value.length < 16)
30071
30347
  return null;
30348
+ if (isCliOptionKeyValue(value))
30349
+ return null;
30072
30350
  return { name: name2, value };
30073
30351
  }
30074
30352
  var STRING_LITERAL_RE = /(["'`])((?:\\.|(?!\1).){8,200})\1/g;
@@ -30275,6 +30553,9 @@ class ScanSecretsPass {
30275
30553
  const m = pattern.regex.exec(lineText);
30276
30554
  if (!m)
30277
30555
  continue;
30556
+ if (pattern.name === "PEM private key" && !pemHasInlineBody(lines, i2)) {
30557
+ continue;
30558
+ }
30278
30559
  const key = `${lineNum}:hardcoded-credential`;
30279
30560
  if (seen.has(key))
30280
30561
  continue;
@@ -31149,6 +31430,9 @@ class WeakCryptoPass {
31149
31430
  run(ctx) {
31150
31431
  const { graph, language, code } = ctx;
31151
31432
  const file = graph.ir.meta.file;
31433
+ if (isProtocolMandatedCryptoFile(file, code)) {
31434
+ return { findings: [] };
31435
+ }
31152
31436
  const findings = [];
31153
31437
  const constProp = ctx.hasResult("constant-propagation") ? ctx.getResult("constant-propagation") : null;
31154
31438
  const literalBindings = scanLiteralBindings(code, language);
@@ -31679,8 +31963,11 @@ class WeakPasswordHashPass {
31679
31963
  name = "weak-password-hash";
31680
31964
  category = "security";
31681
31965
  run(ctx) {
31682
- const { graph, language } = ctx;
31966
+ const { graph, language, code } = ctx;
31683
31967
  const file = graph.ir.meta.file;
31968
+ if (isProtocolMandatedCryptoFile(file, code)) {
31969
+ return { findings: [] };
31970
+ }
31684
31971
  const findings = [];
31685
31972
  for (const call of graph.ir.calls) {
31686
31973
  const detection = this.detect(call, language);
@@ -34824,6 +35111,21 @@ async function analyze(code, filePath, language, options = {}) {
34824
35111
  flows: interProc.additionalFlows,
34825
35112
  interprocedural: interProc.interprocedural
34826
35113
  };
35114
+ if (taint.flows && taint.flows.length > 0 && taint.sinks.length > 0) {
35115
+ const sinkTagsByKey = new Map;
35116
+ for (const s of taint.sinks) {
35117
+ if (!s.tags || s.tags.length === 0)
35118
+ continue;
35119
+ sinkTagsByKey.set(`${s.line}:${s.type}`, s.tags);
35120
+ }
35121
+ if (sinkTagsByKey.size > 0) {
35122
+ for (const f of taint.flows) {
35123
+ const tags = sinkTagsByKey.get(`${f.sink_line}:${f.sink_type}`);
35124
+ if (tags && !f.tags)
35125
+ f.tags = [...tags];
35126
+ }
35127
+ }
35128
+ }
34827
35129
  const unresolved = detectUnresolved(calls, types, dfg);
34828
35130
  const enriched = buildEnriched(types, calls, taint.sources, taint.sinks);
34829
35131
  const metricValues = new MetricRunner().run({ meta, types, calls, cfg, dfg, taint, imports, exports, unresolved, enriched }, code, language);
@@ -34836,7 +35138,8 @@ async function analyze(code, filePath, language, options = {}) {
34836
35138
  });
34837
35139
  emitFindingsInstrumentation(filePath, findings, taint);
34838
35140
  const verifiedFindings = applyConfidenceFilter(findings, options.includeSpeculative === true);
34839
- const cappedFindings = applyPerFileFindingCap(filePath, verifiedFindings, options.perFileFindingCap ?? DEFAULT_PER_FILE_FINDING_CAP);
35141
+ const downgradedFindings = applyLibraryApiSurfaceDowngrade(verifiedFindings);
35142
+ const cappedFindings = applyPerFileFindingCap(filePath, downgradedFindings, options.perFileFindingCap ?? DEFAULT_PER_FILE_FINDING_CAP);
34840
35143
  return {
34841
35144
  meta,
34842
35145
  types,
@@ -35015,9 +35318,17 @@ var colors = {
35015
35318
  };
35016
35319
 
35017
35320
  // src/version.ts
35018
- var version = "3.103.0";
35321
+ var version = "3.105.0";
35019
35322
 
35020
35323
  // src/formatters.ts
35324
+ var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
35325
+ function applyTagSeverityDowngrade(severity, tags) {
35326
+ if (!tags || !tags.includes(LIBRARY_API_SURFACE_TAG2))
35327
+ return severity;
35328
+ if (severity === "critical" || severity === "high")
35329
+ return "medium";
35330
+ return severity;
35331
+ }
35021
35332
  var SINK_SEVERITY = {
35022
35333
  sql_injection: "critical",
35023
35334
  nosql_injection: "high",
@@ -35359,7 +35670,8 @@ function formatResults(results, verbose, crossFileData) {
35359
35670
  const cweTag = vuln.cwe ? ` [${vuln.cwe}]` : "";
35360
35671
  const severityUpper = vuln.severity.charAt(0).toUpperCase() + vuln.severity.slice(1);
35361
35672
  const categoryTag = vuln.category && vuln.category !== "security" ? ` [${vuln.category}]` : "";
35362
- lines.push(` ${colorFn(`[${icon}]`)} ${colorFn(vuln.type)} (${severityUpper})${cweTag}${categoryTag}`);
35673
+ const libraryApiTag = vuln.tags?.includes(LIBRARY_API_SURFACE_TAG2) ? ` ${colors.cyan("[library-api-surface]")}` : "";
35674
+ lines.push(` ${colorFn(`[${icon}]`)} ${colorFn(vuln.type)} (${severityUpper})${cweTag}${categoryTag}${libraryApiTag}`);
35363
35675
  lines.push(` Line ${vuln.line}: ${vuln.message}`);
35364
35676
  const help = VULNERABILITY_HELP[vuln.type];
35365
35677
  const fixText = vuln.fix ?? help?.fix;
@@ -35484,7 +35796,8 @@ function generateSarifResults(results, crossFileData) {
35484
35796
  properties: {
35485
35797
  cwe: vuln.cwe,
35486
35798
  severity: vuln.severity,
35487
- ...vuln.fix ? { fix: vuln.fix } : {}
35799
+ ...vuln.fix ? { fix: vuln.fix } : {},
35800
+ ...vuln.tags && vuln.tags.length > 0 ? { tags: vuln.tags } : {}
35488
35801
  }
35489
35802
  });
35490
35803
  }
@@ -35911,11 +36224,12 @@ async function scanFile(filePath, language, analyzeOpts) {
35911
36224
  });
35912
36225
  const vulnerabilities = (result.taint.flows || []).map((flow) => ({
35913
36226
  type: flow.sink_type,
35914
- severity: SINK_SEVERITY[flow.sink_type] ?? "high",
36227
+ severity: applyTagSeverityDowngrade(SINK_SEVERITY[flow.sink_type] ?? "high", flow.tags),
35915
36228
  message: `${flow.sink_type} vulnerability: tainted data flows from line ${flow.source_line} to line ${flow.sink_line}`,
35916
36229
  line: flow.sink_line,
35917
36230
  cwe: SINK_CWE[flow.sink_type],
35918
- category: "security"
36231
+ category: "security",
36232
+ ...flow.tags && flow.tags.length > 0 ? { tags: [...flow.tags] } : {}
35919
36233
  }));
35920
36234
  for (const finding of result.findings ?? []) {
35921
36235
  vulnerabilities.push({
@@ -35925,7 +36239,8 @@ async function scanFile(filePath, language, analyzeOpts) {
35925
36239
  line: finding.line,
35926
36240
  cwe: finding.cwe,
35927
36241
  fix: finding.fix,
35928
- category: finding.category ?? "reliability"
36242
+ category: finding.category ?? "reliability",
36243
+ ...finding.tags && finding.tags.length > 0 ? { tags: [...finding.tags] } : {}
35929
36244
  });
35930
36245
  }
35931
36246
  return { file: filePath, vulnerabilities };
@@ -35951,11 +36266,12 @@ async function scanProject(files, language, analyzeOpts, crossFileBudgetMs) {
35951
36266
  const results = projectResult.files.map(({ file, analysis }) => {
35952
36267
  const vulnerabilities = (analysis.taint.flows || []).map((flow) => ({
35953
36268
  type: flow.sink_type,
35954
- severity: SINK_SEVERITY[flow.sink_type] ?? "high",
36269
+ severity: applyTagSeverityDowngrade(SINK_SEVERITY[flow.sink_type] ?? "high", flow.tags),
35955
36270
  message: `${flow.sink_type} vulnerability: tainted data flows from line ${flow.source_line} to line ${flow.sink_line}`,
35956
36271
  line: flow.sink_line,
35957
36272
  cwe: SINK_CWE[flow.sink_type],
35958
- category: "security"
36273
+ category: "security",
36274
+ ...flow.tags && flow.tags.length > 0 ? { tags: [...flow.tags] } : {}
35959
36275
  }));
35960
36276
  for (const finding of analysis.findings ?? []) {
35961
36277
  vulnerabilities.push({
@@ -35965,7 +36281,8 @@ async function scanProject(files, language, analyzeOpts, crossFileBudgetMs) {
35965
36281
  line: finding.line,
35966
36282
  cwe: finding.cwe,
35967
36283
  fix: finding.fix,
35968
- category: finding.category ?? "reliability"
36284
+ category: finding.category ?? "reliability",
36285
+ ...finding.tags && finding.tags.length > 0 ? { tags: [...finding.tags] } : {}
35969
36286
  });
35970
36287
  }
35971
36288
  return { file, vulnerabilities };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "3.103.0",
3
+ "version": "3.105.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",
@@ -65,7 +65,7 @@
65
65
  "registry": "https://registry.npmjs.org/"
66
66
  },
67
67
  "dependencies": {
68
- "circle-ir": "^3.103.0"
68
+ "circle-ir": "^3.105.0"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/node": "^25.5.0",