cognium-dev 4.6.0 → 4.7.1
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.
- package/dist/cli.js +205 -20
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -9350,13 +9350,15 @@ function computeChains(defs, uses) {
|
|
|
9350
9350
|
existing.push(use);
|
|
9351
9351
|
usesByLine.set(use.line, existing);
|
|
9352
9352
|
}
|
|
9353
|
+
const seenChains = new Set;
|
|
9353
9354
|
for (const def of defs) {
|
|
9354
9355
|
if (def.kind === "local") {
|
|
9355
9356
|
const usesOnLine = usesByLine.get(def.line) ?? [];
|
|
9356
9357
|
for (const use of usesOnLine) {
|
|
9357
9358
|
if (use.def_id !== null && use.def_id !== def.id) {
|
|
9358
|
-
const
|
|
9359
|
-
if (!
|
|
9359
|
+
const key = `${use.def_id}\x00${def.id}\x00${use.variable}`;
|
|
9360
|
+
if (!seenChains.has(key)) {
|
|
9361
|
+
seenChains.add(key);
|
|
9360
9362
|
chains.push({
|
|
9361
9363
|
from_def: use.def_id,
|
|
9362
9364
|
to_def: def.id,
|
|
@@ -11531,7 +11533,7 @@ var DEFAULT_SINKS = [
|
|
|
11531
11533
|
{ method: "validate", type: "xss", cwe: "CWE-79", severity: "medium", arg_positions: [0] },
|
|
11532
11534
|
{ method: "startElement", class: "ContentHandler", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0, 1, 2] },
|
|
11533
11535
|
{ method: "characters", class: "ContentHandler", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0] },
|
|
11534
|
-
{ method: "output", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0] },
|
|
11536
|
+
{ method: "output", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], exclude_languages: ["rust"] },
|
|
11535
11537
|
{ method: "setOutput", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0] },
|
|
11536
11538
|
{ method: "writeAttribute", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0, 1] },
|
|
11537
11539
|
{ method: "startElement", class: "MagicSAXFilter", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0, 1, 2] },
|
|
@@ -12332,7 +12334,7 @@ var DEFAULT_SINKS = [
|
|
|
12332
12334
|
{ method: "ExecuteScalarAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12333
12335
|
{ method: "ExecuteReaderAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12334
12336
|
{ method: "ExecuteNonQueryAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12335
|
-
{ method: "Start", class: "Process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12337
|
+
{ method: "Start", class: "Process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
|
|
12336
12338
|
{ method: "ProcessStartInfo", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
|
|
12337
12339
|
{ method: "ReadAllText", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12338
12340
|
{ method: "ReadAllBytes", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
@@ -12366,6 +12368,11 @@ var DEFAULT_SINKS = [
|
|
|
12366
12368
|
{ method: "HtmlString", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12367
12369
|
{ method: "DirectorySearcher", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12368
12370
|
{ method: "DirectoryEntry", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12371
|
+
{ method: "Redirect", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["csharp"] },
|
|
12372
|
+
{ method: "RedirectPermanent", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["csharp"] },
|
|
12373
|
+
{ method: "AddHeader", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["csharp"] },
|
|
12374
|
+
{ method: "AppendHeader", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["csharp"] },
|
|
12375
|
+
{ method: "Parse", class: "BsonDocument", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12369
12376
|
{ method: "SelectSingleNode", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12370
12377
|
{ method: "SelectNodes", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12371
12378
|
{ method: "Compile", class: "XPathExpression", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
@@ -25027,6 +25034,7 @@ class LanguageSourcesPass {
|
|
|
25027
25034
|
additionalSources.push(...findSetterChainSources(types, code, language));
|
|
25028
25035
|
additionalSources.push(...findJavaScriptAssignmentSources(code, language));
|
|
25029
25036
|
additionalSources.push(...findCSharpRequestSources(code, language));
|
|
25037
|
+
additionalSources.push(...findGoArgvSources(code, language));
|
|
25030
25038
|
const jsDOMSinks = findJavaScriptDOMSinks(code, language);
|
|
25031
25039
|
for (const s of jsDOMSinks) {
|
|
25032
25040
|
const alreadyExists = additionalSinks.some((x) => x.line === s.line && x.cwe === s.cwe);
|
|
@@ -25629,6 +25637,35 @@ function findSetterChainSources(types, sourceCode, language) {
|
|
|
25629
25637
|
}
|
|
25630
25638
|
return sources;
|
|
25631
25639
|
}
|
|
25640
|
+
function findGoArgvSources(sourceCode, language) {
|
|
25641
|
+
if (language !== "go")
|
|
25642
|
+
return [];
|
|
25643
|
+
const sources = [];
|
|
25644
|
+
const lines = sourceCode.split(`
|
|
25645
|
+
`);
|
|
25646
|
+
const rangeRe = /\bfor\b[^;{]*?,\s*([A-Za-z_]\w*)\s*:?=\s*range\s+os\.Args\b/;
|
|
25647
|
+
const assignRe = /\b([A-Za-z_]\w*)\s*:?=\s*os\.Args\b/;
|
|
25648
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
25649
|
+
const line = lines[i2];
|
|
25650
|
+
const rm = rangeRe.exec(line);
|
|
25651
|
+
const m = rm ?? assignRe.exec(line);
|
|
25652
|
+
if (!m)
|
|
25653
|
+
continue;
|
|
25654
|
+
const varName = m[1];
|
|
25655
|
+
const lineNumber = i2 + 1;
|
|
25656
|
+
if (sources.some((s) => s.line === lineNumber && s.variable === varName))
|
|
25657
|
+
continue;
|
|
25658
|
+
sources.push({
|
|
25659
|
+
type: "io_input",
|
|
25660
|
+
location: `${varName} = os.Args`,
|
|
25661
|
+
severity: "high",
|
|
25662
|
+
line: lineNumber,
|
|
25663
|
+
confidence: 1,
|
|
25664
|
+
variable: varName
|
|
25665
|
+
});
|
|
25666
|
+
}
|
|
25667
|
+
return sources;
|
|
25668
|
+
}
|
|
25632
25669
|
function findCSharpRequestSources(sourceCode, language) {
|
|
25633
25670
|
if (language !== "csharp")
|
|
25634
25671
|
return [];
|
|
@@ -25638,12 +25675,13 @@ function findCSharpRequestSources(sourceCode, language) {
|
|
|
25638
25675
|
const assignRe = /^\s*(?:var\s+|[A-Za-z_][\w.<>\[\]]*\s+)?([A-Za-z_]\w*)\s*=\s*(.+?);?\s*$/;
|
|
25639
25676
|
const requestReadRe = /\bRequest\s*\.\s*(?:Query|Form|Headers|Cookies|QueryString|RouteValues|Body|Files|Params)\b/;
|
|
25640
25677
|
const consoleReadRe = /\bConsole\s*\.\s*ReadLine\s*\(/;
|
|
25678
|
+
const envReadRe = /\bEnvironment\s*\.\s*GetEnvironmentVariables?\s*(?:\(|\[)/;
|
|
25641
25679
|
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
25642
25680
|
const m = assignRe.exec(lines[i2]);
|
|
25643
25681
|
if (!m)
|
|
25644
25682
|
continue;
|
|
25645
25683
|
const [, varName, rhs] = m;
|
|
25646
|
-
const type = requestReadRe.test(rhs) ? "http_param" : consoleReadRe.test(rhs) ? "io_input" : null;
|
|
25684
|
+
const type = requestReadRe.test(rhs) ? "http_param" : consoleReadRe.test(rhs) ? "io_input" : envReadRe.test(rhs) ? "env_input" : null;
|
|
25647
25685
|
if (!type)
|
|
25648
25686
|
continue;
|
|
25649
25687
|
const lineNumber = i2 + 1;
|
|
@@ -26591,7 +26629,7 @@ function findBashTaintSources(sourceCode, dfg) {
|
|
|
26591
26629
|
});
|
|
26592
26630
|
}
|
|
26593
26631
|
}
|
|
26594
|
-
const envRe = /\$([A-Z][A-Z0-9_]{2,})|\$\{([A-Z][A-Z0-9_]{2,})
|
|
26632
|
+
const envRe = /\$([A-Z][A-Z0-9_]{2,})|\$\{([A-Z][A-Z0-9_]{2,})(?:[:#%/^,@!*+?=-][^}]*)?\}/g;
|
|
26595
26633
|
let em;
|
|
26596
26634
|
while ((em = envRe.exec(line)) !== null) {
|
|
26597
26635
|
const envVar = em[1] ?? em[2];
|
|
@@ -33360,7 +33398,10 @@ class SinkFilterPass {
|
|
|
33360
33398
|
const sourceLines = ctx.code.split(`
|
|
33361
33399
|
`);
|
|
33362
33400
|
const sanitizedByType = csharpSanitizedVarsByType(ctx.code);
|
|
33401
|
+
const xxeHardened = /\bXmlResolver\s*=\s*null\b/.test(ctx.code) || /\bDtdProcessing\s*=\s*(?:DtdProcessing\s*\.\s*)?(?:Prohibit|Ignore)\b/.test(ctx.code);
|
|
33363
33402
|
filtered = filtered.filter((sink) => {
|
|
33403
|
+
if (sink.type === "xxe" && xxeHardened)
|
|
33404
|
+
return false;
|
|
33364
33405
|
const sinkLineText = sourceLines[sink.line - 1] ?? "";
|
|
33365
33406
|
for (const { re, type } of CSHARP_SANITIZER_RES) {
|
|
33366
33407
|
if (type === sink.type && re.test(sinkLineText))
|
|
@@ -36410,6 +36451,26 @@ function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourc
|
|
|
36410
36451
|
"Command",
|
|
36411
36452
|
"CommandContext"
|
|
36412
36453
|
]);
|
|
36454
|
+
const ormQueryBuilderMethods = new Set([
|
|
36455
|
+
"findMany",
|
|
36456
|
+
"findFirst",
|
|
36457
|
+
"findUnique",
|
|
36458
|
+
"findUniqueOrThrow",
|
|
36459
|
+
"findFirstOrThrow",
|
|
36460
|
+
"findOne",
|
|
36461
|
+
"findAll",
|
|
36462
|
+
"findByPk",
|
|
36463
|
+
"findAndCountAll",
|
|
36464
|
+
"findBy",
|
|
36465
|
+
"findOneBy",
|
|
36466
|
+
"where",
|
|
36467
|
+
"andWhere",
|
|
36468
|
+
"orWhere",
|
|
36469
|
+
"whereIn",
|
|
36470
|
+
"whereNot",
|
|
36471
|
+
"first",
|
|
36472
|
+
"bind"
|
|
36473
|
+
]);
|
|
36413
36474
|
const sanitizerMethods = new Set;
|
|
36414
36475
|
for (const san of sanitizers) {
|
|
36415
36476
|
sanitizerMethods.add(san.method);
|
|
@@ -36434,7 +36495,7 @@ function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourc
|
|
|
36434
36495
|
}
|
|
36435
36496
|
const targetMethod = getMethodNode(methodNodes, call.method_name);
|
|
36436
36497
|
if (!targetMethod) {
|
|
36437
|
-
if (taintedArgPositions.length > 0 && !collectionMethods.has(call.method_name) && !sanitizerMethods.has(call.method_name) && !safeUtilityMethods.has(call.method_name)) {
|
|
36498
|
+
if (taintedArgPositions.length > 0 && !collectionMethods.has(call.method_name) && !sanitizerMethods.has(call.method_name) && !safeUtilityMethods.has(call.method_name) && !ormQueryBuilderMethods.has(call.method_name)) {
|
|
36438
36499
|
const isBash = graph.ir.meta.language === "bash";
|
|
36439
36500
|
const bashSafeBuiltins = new Set([
|
|
36440
36501
|
"echo",
|
|
@@ -37234,6 +37295,8 @@ function isPublicMethod(method, language) {
|
|
|
37234
37295
|
switch (language) {
|
|
37235
37296
|
case "java":
|
|
37236
37297
|
return method.modifiers.includes("public");
|
|
37298
|
+
case "csharp":
|
|
37299
|
+
return method.modifiers.includes("public");
|
|
37237
37300
|
case "javascript":
|
|
37238
37301
|
case "typescript":
|
|
37239
37302
|
case "tsx":
|
|
@@ -37256,7 +37319,7 @@ class MissingPublicDocPass {
|
|
|
37256
37319
|
if (UTIL_DIR_RE.test(graph.ir.meta.file)) {
|
|
37257
37320
|
return { missingDocMethods: [], missingDocTypes: [] };
|
|
37258
37321
|
}
|
|
37259
|
-
if (!["java", "javascript", "typescript", "tsx", "python"].includes(language)) {
|
|
37322
|
+
if (!["java", "javascript", "typescript", "tsx", "python", "csharp"].includes(language)) {
|
|
37260
37323
|
return { missingDocMethods: [], missingDocTypes: [] };
|
|
37261
37324
|
}
|
|
37262
37325
|
const lines = code.split(`
|
|
@@ -38222,6 +38285,7 @@ var SKIP_NAMES3 = new Set([
|
|
|
38222
38285
|
"unknown",
|
|
38223
38286
|
"bigint"
|
|
38224
38287
|
]);
|
|
38288
|
+
var EMPTY_LINES = [];
|
|
38225
38289
|
|
|
38226
38290
|
class UnusedVariablePass {
|
|
38227
38291
|
name = "unused-variable";
|
|
@@ -38236,6 +38300,35 @@ class UnusedVariablePass {
|
|
|
38236
38300
|
`);
|
|
38237
38301
|
const unusedVars = [];
|
|
38238
38302
|
const reported = new Set;
|
|
38303
|
+
const defsByVar = new Map;
|
|
38304
|
+
for (const d of graph.ir.dfg.defs) {
|
|
38305
|
+
const arr = defsByVar.get(d.variable);
|
|
38306
|
+
if (arr)
|
|
38307
|
+
arr.push(d);
|
|
38308
|
+
else
|
|
38309
|
+
defsByVar.set(d.variable, [d]);
|
|
38310
|
+
}
|
|
38311
|
+
const nameLines = new Map;
|
|
38312
|
+
const idRe = /[A-Za-z_][A-Za-z0-9_]*/g;
|
|
38313
|
+
for (let i2 = 0;i2 < codeLines.length; i2++) {
|
|
38314
|
+
const line = codeLines[i2];
|
|
38315
|
+
idRe.lastIndex = 0;
|
|
38316
|
+
let seen = null;
|
|
38317
|
+
let m;
|
|
38318
|
+
while ((m = idRe.exec(line)) !== null) {
|
|
38319
|
+
const w = m[0];
|
|
38320
|
+
if (seen === null)
|
|
38321
|
+
seen = new Set;
|
|
38322
|
+
if (seen.has(w))
|
|
38323
|
+
continue;
|
|
38324
|
+
seen.add(w);
|
|
38325
|
+
const arr = nameLines.get(w);
|
|
38326
|
+
if (arr)
|
|
38327
|
+
arr.push(i2 + 1);
|
|
38328
|
+
else
|
|
38329
|
+
nameLines.set(w, [i2 + 1]);
|
|
38330
|
+
}
|
|
38331
|
+
}
|
|
38239
38332
|
for (const def of graph.ir.dfg.defs) {
|
|
38240
38333
|
if (def.kind !== "local")
|
|
38241
38334
|
continue;
|
|
@@ -38252,19 +38345,20 @@ class UnusedVariablePass {
|
|
|
38252
38345
|
const uses = graph.usesOfDef(def.id);
|
|
38253
38346
|
if (uses.length > 0)
|
|
38254
38347
|
continue;
|
|
38255
|
-
const otherDefs =
|
|
38348
|
+
const otherDefs = (defsByVar.get(variable) ?? []).filter((d) => d.id !== def.id);
|
|
38256
38349
|
const otherDefLines = new Set(otherDefs.map((d) => d.line));
|
|
38257
|
-
const
|
|
38258
|
-
const
|
|
38350
|
+
const plainName = /^[A-Za-z_][A-Za-z0-9_]*$/.test(variable);
|
|
38351
|
+
const idxLines = plainName ? nameLines.get(variable) ?? EMPTY_LINES : null;
|
|
38352
|
+
const namePattern = plainName ? null : new RegExp(`\\b${variable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`);
|
|
38259
38353
|
if (otherDefLines.size === 0) {
|
|
38260
|
-
const usedElsewhere = codeLines.some((line, idx) => idx !== def.line - 1 && namePattern.test(line));
|
|
38354
|
+
const usedElsewhere = idxLines !== null ? idxLines.some((ln) => ln !== def.line) : codeLines.some((line, idx) => idx !== def.line - 1 && namePattern.test(line));
|
|
38261
38355
|
if (usedElsewhere)
|
|
38262
38356
|
continue;
|
|
38263
38357
|
} else {
|
|
38264
38358
|
const lineText2 = codeLines[def.line - 1] ?? "";
|
|
38265
38359
|
const isTrueDeclaration = /\b(?:let|const|var)\s+[\w{[]/.test(lineText2) || /\b(?:int|long|float|double|boolean|byte|char|short|var|final)\b/.test(lineText2) || /\b[A-Z]\w*(?:<[^>]*>)?\s+\w/.test(lineText2) || /\blet\s+(?:mut\s+)?\w/.test(lineText2);
|
|
38266
38360
|
if (isTrueDeclaration) {
|
|
38267
|
-
const usedBeforeNextDef = codeLines.some((line, idx) => {
|
|
38361
|
+
const usedBeforeNextDef = idxLines !== null ? idxLines.some((ln) => ln !== def.line && !otherDefLines.has(ln) && !otherDefs.some((d) => d.line > def.line && d.line < ln)) : codeLines.some((line, idx) => {
|
|
38268
38362
|
const lineNum = idx + 1;
|
|
38269
38363
|
if (lineNum === def.line || otherDefLines.has(lineNum))
|
|
38270
38364
|
return false;
|
|
@@ -38275,7 +38369,7 @@ class UnusedVariablePass {
|
|
|
38275
38369
|
if (usedBeforeNextDef)
|
|
38276
38370
|
continue;
|
|
38277
38371
|
} else {
|
|
38278
|
-
const usedOnNonDefLine = codeLines.some((line, idx) => {
|
|
38372
|
+
const usedOnNonDefLine = idxLines !== null ? idxLines.some((ln) => ln !== def.line && !otherDefLines.has(ln)) : codeLines.some((line, idx) => {
|
|
38279
38373
|
const lineNum = idx + 1;
|
|
38280
38374
|
return lineNum !== def.line && !otherDefLines.has(lineNum) && namePattern.test(line);
|
|
38281
38375
|
});
|
|
@@ -42231,6 +42325,30 @@ var WEAK_HASH_NAMES = new Set([
|
|
|
42231
42325
|
"sha-1",
|
|
42232
42326
|
"sha1"
|
|
42233
42327
|
]);
|
|
42328
|
+
var CSHARP_WEAK_HASH_CLASSES = new Set(["MD5", "SHA1"]);
|
|
42329
|
+
var CSHARP_HASH_FACTORY_RECEIVERS = new Set([
|
|
42330
|
+
"HashAlgorithm",
|
|
42331
|
+
"KeyedHashAlgorithm",
|
|
42332
|
+
"HMAC",
|
|
42333
|
+
"CryptoConfig"
|
|
42334
|
+
]);
|
|
42335
|
+
var CSHARP_WEAK_HASH_CTORS = {
|
|
42336
|
+
MD5CryptoServiceProvider: "md5",
|
|
42337
|
+
MD5Cng: "md5",
|
|
42338
|
+
SHA1CryptoServiceProvider: "sha1",
|
|
42339
|
+
SHA1Managed: "sha1",
|
|
42340
|
+
SHA1Cng: "sha1",
|
|
42341
|
+
HMACMD5: "md5",
|
|
42342
|
+
HMACSHA1: "sha1"
|
|
42343
|
+
};
|
|
42344
|
+
function csharpWeakHashAlgo(cleaned) {
|
|
42345
|
+
if (!cleaned)
|
|
42346
|
+
return null;
|
|
42347
|
+
const base = (cleaned.split(".").pop() ?? cleaned).replace(/^hmac/, "");
|
|
42348
|
+
if (base === "sha")
|
|
42349
|
+
return "sha1";
|
|
42350
|
+
return WEAK_HASH_NAMES.has(base) ? base : null;
|
|
42351
|
+
}
|
|
42234
42352
|
var COMMONS_DIGEST_METHODS = new Set([
|
|
42235
42353
|
"md2",
|
|
42236
42354
|
"md2Hex",
|
|
@@ -42401,6 +42519,20 @@ class WeakHashPass {
|
|
|
42401
42519
|
}
|
|
42402
42520
|
return null;
|
|
42403
42521
|
}
|
|
42522
|
+
if (language === "csharp") {
|
|
42523
|
+
if ((method === "Create" || method === "HashData") && CSHARP_WEAK_HASH_CLASSES.has(receiver)) {
|
|
42524
|
+
return { algorithm: receiver.toLowerCase(), api: `${receiver}.${method}` };
|
|
42525
|
+
}
|
|
42526
|
+
if ((method === "Create" || method === "CreateFromName") && CSHARP_HASH_FACTORY_RECEIVERS.has(receiver)) {
|
|
42527
|
+
const algo = csharpWeakHashAlgo(literalAlgo(call, 0));
|
|
42528
|
+
if (algo)
|
|
42529
|
+
return { algorithm: algo, api: `${receiver}.${method}` };
|
|
42530
|
+
}
|
|
42531
|
+
if (call.is_constructor && CSHARP_WEAK_HASH_CTORS[method]) {
|
|
42532
|
+
return { algorithm: CSHARP_WEAK_HASH_CTORS[method], api: `new ${method}()` };
|
|
42533
|
+
}
|
|
42534
|
+
return null;
|
|
42535
|
+
}
|
|
42404
42536
|
return null;
|
|
42405
42537
|
}
|
|
42406
42538
|
}
|
|
@@ -42457,6 +42589,30 @@ var WEAK_CIPHER_BASES = new Set([
|
|
|
42457
42589
|
"seed",
|
|
42458
42590
|
"cast5"
|
|
42459
42591
|
]);
|
|
42592
|
+
var CSHARP_WEAK_CIPHER_CLASSES = new Set(["DES", "TripleDES", "RC2", "RC4"]);
|
|
42593
|
+
var CSHARP_CIPHER_FACTORY_RECEIVERS = new Set(["SymmetricAlgorithm", "CryptoConfig"]);
|
|
42594
|
+
var CSHARP_WEAK_CIPHER_CTORS = {
|
|
42595
|
+
DESCryptoServiceProvider: "des",
|
|
42596
|
+
TripleDESCryptoServiceProvider: "3des",
|
|
42597
|
+
RC2CryptoServiceProvider: "rc2"
|
|
42598
|
+
};
|
|
42599
|
+
var CSHARP_RSA_FACTORY_CLASSES = new Set(["RSA", "DSA"]);
|
|
42600
|
+
var CSHARP_RSA_CTORS = new Set([
|
|
42601
|
+
"RSACryptoServiceProvider",
|
|
42602
|
+
"DSACryptoServiceProvider",
|
|
42603
|
+
"RSACng",
|
|
42604
|
+
"DSACng"
|
|
42605
|
+
]);
|
|
42606
|
+
function csharpWeakCipher(cleaned) {
|
|
42607
|
+
if (!cleaned)
|
|
42608
|
+
return null;
|
|
42609
|
+
const base = (cleaned.split(".").pop() ?? cleaned).toLowerCase();
|
|
42610
|
+
if (base === "tripledes" || base === "desede")
|
|
42611
|
+
return "3des";
|
|
42612
|
+
if (base === "arc4")
|
|
42613
|
+
return "rc4";
|
|
42614
|
+
return WEAK_CIPHER_BASES.has(base) ? base : null;
|
|
42615
|
+
}
|
|
42460
42616
|
function classifyJavaCipherSpec(spec) {
|
|
42461
42617
|
const parts2 = spec.split("/").map((p) => p.trim().toLowerCase());
|
|
42462
42618
|
const base = parts2[0] ?? "";
|
|
@@ -42880,6 +43036,35 @@ class WeakCryptoPass {
|
|
|
42880
43036
|
}
|
|
42881
43037
|
return out2;
|
|
42882
43038
|
}
|
|
43039
|
+
if (language === "csharp") {
|
|
43040
|
+
if (method === "Create" && CSHARP_WEAK_CIPHER_CLASSES.has(receiver)) {
|
|
43041
|
+
const base = receiver === "TripleDES" ? "3des" : receiver.toLowerCase();
|
|
43042
|
+
out2.push({ issue: "weak-cipher", detail: base, api: `${receiver}.Create` });
|
|
43043
|
+
}
|
|
43044
|
+
if ((method === "Create" || method === "CreateFromName") && CSHARP_CIPHER_FACTORY_RECEIVERS.has(receiver)) {
|
|
43045
|
+
const base = csharpWeakCipher(literalAlgo2(call, 0));
|
|
43046
|
+
if (base)
|
|
43047
|
+
out2.push({ issue: "weak-cipher", detail: base, api: `${receiver}.${method}` });
|
|
43048
|
+
}
|
|
43049
|
+
if (call.is_constructor && CSHARP_WEAK_CIPHER_CTORS[method]) {
|
|
43050
|
+
out2.push({ issue: "weak-cipher", detail: CSHARP_WEAK_CIPHER_CTORS[method], api: `new ${method}()` });
|
|
43051
|
+
}
|
|
43052
|
+
const rsaFactory = method === "Create" && CSHARP_RSA_FACTORY_CLASSES.has(receiver);
|
|
43053
|
+
const rsaCtor = call.is_constructor && CSHARP_RSA_CTORS.has(method);
|
|
43054
|
+
if (rsaFactory || rsaCtor) {
|
|
43055
|
+
const sizeArg = call.arguments.find((a) => a.position === 0);
|
|
43056
|
+
const expr = (sizeArg?.literal ?? sizeArg?.expression ?? "").trim();
|
|
43057
|
+
const n = parseInt(expr, 10);
|
|
43058
|
+
if (Number.isFinite(n) && n > 0 && n < 2048) {
|
|
43059
|
+
out2.push({
|
|
43060
|
+
issue: "weak-rsa-key",
|
|
43061
|
+
detail: String(n),
|
|
43062
|
+
api: rsaCtor ? `new ${method}()` : `${receiver}.Create`
|
|
43063
|
+
});
|
|
43064
|
+
}
|
|
43065
|
+
}
|
|
43066
|
+
return out2;
|
|
43067
|
+
}
|
|
42883
43068
|
return out2;
|
|
42884
43069
|
}
|
|
42885
43070
|
}
|
|
@@ -43610,9 +43795,7 @@ class InfoDisclosureStacktracePass {
|
|
|
43610
43795
|
// ../circle-ir/dist/analysis/passes/unrestricted-file-upload-pass.js
|
|
43611
43796
|
var UPLOAD_NAME_RE = /(?:getOriginalFilename|getSubmittedFileName|originalname|originalName|\.filename|\.Filename|FileHeader\.Filename|UploadFile)/;
|
|
43612
43797
|
var FILE_SAFE_CALL_RE = /(?:secure_filename|FilenameUtils\.getExtension|\.lastIndexOf\(['"]\.['"]\)|ALLOWED_EXT|ALLOWED_EXTENSIONS|allowedExtensions|\bfileFilter\b|filepath\.Ext|path\.extname)/;
|
|
43613
|
-
function lineWindow(
|
|
43614
|
-
const lines = code.split(`
|
|
43615
|
-
`);
|
|
43798
|
+
function lineWindow(lines, startLine, endLine) {
|
|
43616
43799
|
const s = Math.max(0, startLine - 1);
|
|
43617
43800
|
const e = Math.min(lines.length, endLine);
|
|
43618
43801
|
return lines.slice(s, e).join(`
|
|
@@ -43636,10 +43819,12 @@ class UnrestrictedFileUploadPass {
|
|
|
43636
43819
|
const { graph, language, code } = ctx;
|
|
43637
43820
|
const file = graph.ir.meta.file;
|
|
43638
43821
|
const findings = [];
|
|
43822
|
+
const codeLines = code.split(`
|
|
43823
|
+
`);
|
|
43639
43824
|
const safeFunctionRanges = [];
|
|
43640
43825
|
for (const t of graph.ir.types) {
|
|
43641
43826
|
for (const m of t.methods) {
|
|
43642
|
-
const body2 = lineWindow(
|
|
43827
|
+
const body2 = lineWindow(codeLines, m.start_line, m.end_line);
|
|
43643
43828
|
if (FILE_SAFE_CALL_RE.test(body2)) {
|
|
43644
43829
|
safeFunctionRanges.push({ start: m.start_line, end: m.end_line });
|
|
43645
43830
|
}
|
|
@@ -43650,7 +43835,7 @@ class UnrestrictedFileUploadPass {
|
|
|
43650
43835
|
if (line >= r.start && line <= r.end)
|
|
43651
43836
|
return true;
|
|
43652
43837
|
}
|
|
43653
|
-
const win = lineWindow(
|
|
43838
|
+
const win = lineWindow(codeLines, Math.max(1, line - 20), line + 5);
|
|
43654
43839
|
return FILE_SAFE_CALL_RE.test(win);
|
|
43655
43840
|
};
|
|
43656
43841
|
if (language === "java") {
|
|
@@ -47900,7 +48085,7 @@ var colors = {
|
|
|
47900
48085
|
};
|
|
47901
48086
|
|
|
47902
48087
|
// src/version.ts
|
|
47903
|
-
var version = "4.
|
|
48088
|
+
var version = "4.7.1";
|
|
47904
48089
|
|
|
47905
48090
|
// src/formatters.ts
|
|
47906
48091
|
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": "4.
|
|
3
|
+
"version": "4.7.1",
|
|
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": "^4.
|
|
69
|
+
"circle-ir": "^4.7.1"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/node": "^25.5.0",
|