cognium-dev 3.96.0 → 3.98.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 +144 -1
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -12138,6 +12138,134 @@ function isFunctionCallbackArgument(arg) {
12138
12138
  return true;
12139
12139
  return false;
12140
12140
  }
12141
+ function findGoLocalDeclaredType(varName, callLine, sourceLines) {
12142
+ if (!varName)
12143
+ return null;
12144
+ const WINDOW = 50;
12145
+ const startIdx = Math.max(0, callLine - 2);
12146
+ const endIdx = Math.max(0, startIdx - WINDOW);
12147
+ const name2 = varName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
12148
+ const VAR_DECL_RE = new RegExp(`^\\s*var\\s+${name2}\\s+([^=\\n][^\\n]*)$`);
12149
+ const VAR_INIT_RE = new RegExp(`^\\s*var\\s+${name2}(?:\\s+[^=\\n]*?)?\\s*=\\s*(.+)$`);
12150
+ const SHORT_INIT_RE = new RegExp(`^\\s*${name2}\\s*:=\\s*(.+)$`);
12151
+ for (let i2 = startIdx;i2 >= endIdx; i2--) {
12152
+ const raw = sourceLines[i2];
12153
+ if (raw === undefined)
12154
+ continue;
12155
+ const line = raw.replace(/\/\/.*$/, "").trimEnd();
12156
+ let m = VAR_DECL_RE.exec(line);
12157
+ if (m) {
12158
+ return { kind: "typed-decl", text: m[1].trim() };
12159
+ }
12160
+ m = VAR_INIT_RE.exec(line);
12161
+ if (m) {
12162
+ return classifyGoRhs(m[1].trim());
12163
+ }
12164
+ m = SHORT_INIT_RE.exec(line);
12165
+ if (m) {
12166
+ return classifyGoRhs(m[1].trim());
12167
+ }
12168
+ }
12169
+ return null;
12170
+ }
12171
+ function classifyGoRhs(rhs) {
12172
+ const body2 = rhs.startsWith("&") ? rhs.slice(1).trimStart() : rhs;
12173
+ if (/^make\s*\(/.test(body2)) {
12174
+ return { kind: "untyped" };
12175
+ }
12176
+ const parenIdx = body2.indexOf("(");
12177
+ const braceIdx = body2.indexOf("{");
12178
+ if (parenIdx >= 0 && (braceIdx < 0 || parenIdx < braceIdx)) {
12179
+ return { kind: "untyped" };
12180
+ }
12181
+ if (braceIdx > 0) {
12182
+ const tag = body2.slice(0, braceIdx).trim();
12183
+ if (tag.length > 0) {
12184
+ if (/\binterface\s*\{\s*\}/.test(tag))
12185
+ return { kind: "untyped" };
12186
+ if (/\bany\b/.test(tag))
12187
+ return { kind: "untyped" };
12188
+ return { kind: "typed-init", text: tag };
12189
+ }
12190
+ }
12191
+ return { kind: "untyped" };
12192
+ }
12193
+ function classifyGoDestinationType(decl) {
12194
+ if (decl === null)
12195
+ return "unknown";
12196
+ if (decl.kind === "untyped")
12197
+ return "unknown";
12198
+ const text = decl.text;
12199
+ if (/\binterface\s*\{\s*\}/.test(text))
12200
+ return "unsafe";
12201
+ if (/\bany\b/.test(text))
12202
+ return "unsafe";
12203
+ return "safe";
12204
+ }
12205
+ function isSafeGoJsonUnmarshalCall(call, pattern, language, sourceLines) {
12206
+ if (language !== "go")
12207
+ return false;
12208
+ if (pattern.type !== "deserialization")
12209
+ return false;
12210
+ if (!sourceLines)
12211
+ return false;
12212
+ const method = call.method_name;
12213
+ let destPos;
12214
+ if (method === "Unmarshal" && pattern.class === "json") {
12215
+ destPos = 1;
12216
+ } else if (method === "Decode" && pattern.class === "Decoder") {
12217
+ destPos = 0;
12218
+ } else {
12219
+ return false;
12220
+ }
12221
+ const destArg = call.arguments.find((a) => a.position === destPos);
12222
+ if (!destArg)
12223
+ return false;
12224
+ const expr = (destArg.expression ?? "").trim();
12225
+ if (expr.length === 0)
12226
+ return false;
12227
+ if (expr.startsWith("&")) {
12228
+ const inner = expr.slice(1).trimStart();
12229
+ const compIdx = inner.indexOf("{");
12230
+ if (compIdx > 0) {
12231
+ const decl2 = { kind: "typed-init", text: inner.slice(0, compIdx).trim() };
12232
+ return classifyGoDestinationType(decl2) === "safe";
12233
+ }
12234
+ const m = /^&([A-Za-z_]\w*)$/.exec(expr);
12235
+ if (!m)
12236
+ return false;
12237
+ const varName = m[1];
12238
+ const decl = findGoLocalDeclaredType(varName, call.location.line, sourceLines);
12239
+ return classifyGoDestinationType(decl) === "safe";
12240
+ }
12241
+ const idMatch = /^([A-Za-z_]\w*)$/.exec(expr);
12242
+ if (idMatch) {
12243
+ const decl = findGoLocalDeclaredType(idMatch[1], call.location.line, sourceLines);
12244
+ return classifyGoDestinationType(decl) === "safe";
12245
+ }
12246
+ return false;
12247
+ }
12248
+ var TEMPLATE_LITERAL_RECEIVER_RE = /^Template\(\s*(?:"[^"\\]*"|'[^'\\]*')\s*\)$/;
12249
+ function isSafeJinjaRenderCall(call, pattern, language) {
12250
+ if (language !== "python")
12251
+ return false;
12252
+ if (pattern.type !== "xss" && pattern.type !== "code_injection")
12253
+ return false;
12254
+ const method = call.method_name;
12255
+ if (method === "render_template_string") {
12256
+ const arg0 = call.arguments.find((a) => a.position === 0);
12257
+ return typeof arg0?.literal === "string";
12258
+ }
12259
+ if (method === "Template" || method === "from_string") {
12260
+ const arg0 = call.arguments.find((a) => a.position === 0);
12261
+ return typeof arg0?.literal === "string";
12262
+ }
12263
+ if (method === "render") {
12264
+ const receiver = (call.receiver ?? "").trim();
12265
+ return TEMPLATE_LITERAL_RECEIVER_RE.test(receiver);
12266
+ }
12267
+ return false;
12268
+ }
12141
12269
  function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
12142
12270
  const sinkMap = new Map;
12143
12271
  for (const call of calls) {
@@ -12176,6 +12304,12 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
12176
12304
  continue;
12177
12305
  }
12178
12306
  }
12307
+ if (isSafeGoJsonUnmarshalCall(call, pattern, language, sourceLines)) {
12308
+ continue;
12309
+ }
12310
+ if (isSafeJinjaRenderCall(call, pattern, language)) {
12311
+ continue;
12312
+ }
12179
12313
  const location = formatCallLocation(call);
12180
12314
  const key = `${location}:${call.location.line}:${pattern.cwe}`;
12181
12315
  const confidence = calculateSinkConfidence(call, pattern);
@@ -22601,6 +22735,13 @@ function findPythonTrustBoundaryViolations(sourceCode, taintedVars) {
22601
22735
  }
22602
22736
  return violations;
22603
22737
  }
22738
+ var JINJA_LITERAL_ARG_RE_FRAG = `(?:"[^"\\\\]*"|'[^'\\\\]*')`;
22739
+ var JINJA_SAFE_RTS_RE = new RegExp(`^(?:flask\\.|jinja2\\.)?render_template_string\\s*\\(\\s*${JINJA_LITERAL_ARG_RE_FRAG}\\s*[,)]`);
22740
+ var JINJA_SAFE_TEMPLATE_RE = new RegExp(`^(?:jinja2\\.)?Template\\s*\\(\\s*${JINJA_LITERAL_ARG_RE_FRAG}\\s*\\)(?:\\s*\\.render\\s*\\(|\\s*$)`);
22741
+ function isSafeJinjaReturnExpr(expr) {
22742
+ const trimmed = expr.trim();
22743
+ return JINJA_SAFE_RTS_RE.test(trimmed) || JINJA_SAFE_TEMPLATE_RE.test(trimmed);
22744
+ }
22604
22745
  function findPythonReturnXSSSinks(sourceCode, taintedVars) {
22605
22746
  if (taintedVars.size === 0)
22606
22747
  return [];
@@ -22622,6 +22763,8 @@ function findPythonReturnXSSSinks(sourceCode, taintedVars) {
22622
22763
  const looksLikeHTML = expr.includes("<") || /['"]\s*\+/.test(expr) || /\+\s*['"]/.test(expr) || /f['"][^'"]*\{/.test(expr);
22623
22764
  if (!looksLikeHTML)
22624
22765
  continue;
22766
+ if (isSafeJinjaReturnExpr(expr))
22767
+ continue;
22625
22768
  sinks.push({ sinkLine: i2 + 1 });
22626
22769
  }
22627
22770
  return sinks;
@@ -34598,7 +34741,7 @@ var colors = {
34598
34741
  };
34599
34742
 
34600
34743
  // src/version.ts
34601
- var version = "3.96.0";
34744
+ var version = "3.98.0";
34602
34745
 
34603
34746
  // src/formatters.ts
34604
34747
  var SINK_SEVERITY = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "3.96.0",
3
+ "version": "3.98.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.96.0"
68
+ "circle-ir": "^3.98.0"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/node": "^25.5.0",