cognium-dev 4.14.1 → 4.14.2
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 +264 -43
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -7421,6 +7421,17 @@ function extractGoCallInfo(node) {
|
|
|
7421
7421
|
if (operand.type === "identifier") {
|
|
7422
7422
|
const resolved = resolveGoLocalReceiverType(opText, node);
|
|
7423
7423
|
receiver = resolved !== null ? resolved : opText;
|
|
7424
|
+
} else if (operand.type === "selector_expression" && methodName === "Get") {
|
|
7425
|
+
const fieldNode = operand.childForFieldName("field");
|
|
7426
|
+
const inner = operand.childForFieldName("operand");
|
|
7427
|
+
const fieldName = fieldNode ? getNodeText(fieldNode) : "";
|
|
7428
|
+
const innerName = inner && inner.type === "identifier" ? getNodeText(inner) : null;
|
|
7429
|
+
const innerType = innerName !== null ? resolveGoLocalReceiverType(innerName, node) : null;
|
|
7430
|
+
if (innerType === "Request" && (fieldName === "PostForm" || fieldName === "Form")) {
|
|
7431
|
+
receiver = fieldName === "PostForm" ? "RequestPostForm" : "RequestForm";
|
|
7432
|
+
} else {
|
|
7433
|
+
receiver = opText;
|
|
7434
|
+
}
|
|
7424
7435
|
} else {
|
|
7425
7436
|
receiver = opText;
|
|
7426
7437
|
}
|
|
@@ -12048,7 +12059,11 @@ var DEFAULT_SINKS = [
|
|
|
12048
12059
|
{ method: "setExpireTimeSeconds", class: "StaticFilesConfiguration", type: "path_traversal", cwe: "CWE-22", severity: "medium", arg_positions: [0] },
|
|
12049
12060
|
{ method: "configureJarCase", class: "StaticFilesConfiguration", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
12050
12061
|
{ method: "toString", class: "StringUtils", type: "path_traversal", cwe: "CWE-22", severity: "medium", arg_positions: [0] },
|
|
12051
|
-
{ method: "getResource", class: "ServletResourceManager", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
12062
|
+
{ method: "getResource", class: "ServletResourceManager", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["java"] },
|
|
12063
|
+
{ method: "getResource", class: "ResourceManager", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["java"] },
|
|
12064
|
+
{ method: "getResource", class: "PathResourceManager", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["java"] },
|
|
12065
|
+
{ method: "getResource", class: "FileResourceManager", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["java"] },
|
|
12066
|
+
{ method: "getResource", class: "ClassPathResourceManager", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["java"] },
|
|
12052
12067
|
{ method: "deleteObject", class: "FileSystemBucket", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
12053
12068
|
{ method: "regularExpressionMatcher", class: "Validators", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
12054
12069
|
{ method: "checkMessage", class: "Validators", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
@@ -14049,7 +14064,8 @@ function isInterproceduralTaintableType(typeName, language) {
|
|
|
14049
14064
|
function isParameterizedQueryCall(call, pattern) {
|
|
14050
14065
|
if (pattern.type !== "sql_injection")
|
|
14051
14066
|
return false;
|
|
14052
|
-
const
|
|
14067
|
+
const positions = pattern.arg_positions ?? [];
|
|
14068
|
+
const queryPos = positions.length > 0 ? Math.min(...positions) : 0;
|
|
14053
14069
|
const queryArg = call.arguments.find((a) => a.position === queryPos);
|
|
14054
14070
|
if (queryArg) {
|
|
14055
14071
|
const queryText = queryArg.literal ?? queryArg.expression ?? "";
|
|
@@ -18374,7 +18390,17 @@ function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanit
|
|
|
18374
18390
|
}
|
|
18375
18391
|
const taintInfo = taintByDefId.get(use.def_id);
|
|
18376
18392
|
if (taintInfo) {
|
|
18377
|
-
|
|
18393
|
+
let sanMap = sanitizersByLine;
|
|
18394
|
+
if (identifierOutsideSanitizerCalls(use.variable, callsAtSink, sanitizersByLine.get(sink.line) ?? [], sink.type)) {
|
|
18395
|
+
const stripped = new Map(sanitizersByLine);
|
|
18396
|
+
const kept = (sanitizersByLine.get(sink.line) ?? []).filter((s) => !sanitizerCoversSink(s, sink.type));
|
|
18397
|
+
if (kept.length === 0)
|
|
18398
|
+
stripped.delete(sink.line);
|
|
18399
|
+
else
|
|
18400
|
+
stripped.set(sink.line, kept);
|
|
18401
|
+
sanMap = stripped;
|
|
18402
|
+
}
|
|
18403
|
+
const isSanitized = checkSanitized(taintInfo.line, sink.line, sink.type, sanMap, {
|
|
18378
18404
|
startDefId: use.def_id,
|
|
18379
18405
|
chainsByToDef: graph.chainsByToDef,
|
|
18380
18406
|
defById
|
|
@@ -18520,6 +18546,97 @@ var KNOWN_SINK_TYPES = new Set([
|
|
|
18520
18546
|
"crlf",
|
|
18521
18547
|
"mass_assignment"
|
|
18522
18548
|
]);
|
|
18549
|
+
function readBalancedArg(text, openParen) {
|
|
18550
|
+
let depth = 0;
|
|
18551
|
+
let quote = null;
|
|
18552
|
+
let escaped = false;
|
|
18553
|
+
for (let i2 = openParen;i2 < text.length; i2++) {
|
|
18554
|
+
const c = text[i2];
|
|
18555
|
+
if (quote) {
|
|
18556
|
+
if (escaped) {
|
|
18557
|
+
escaped = false;
|
|
18558
|
+
continue;
|
|
18559
|
+
}
|
|
18560
|
+
if (c === "\\") {
|
|
18561
|
+
escaped = true;
|
|
18562
|
+
continue;
|
|
18563
|
+
}
|
|
18564
|
+
if (c === quote)
|
|
18565
|
+
quote = null;
|
|
18566
|
+
continue;
|
|
18567
|
+
}
|
|
18568
|
+
if (c === '"' || c === "'") {
|
|
18569
|
+
quote = c;
|
|
18570
|
+
continue;
|
|
18571
|
+
}
|
|
18572
|
+
if (c === "(")
|
|
18573
|
+
depth++;
|
|
18574
|
+
else if (c === ")") {
|
|
18575
|
+
depth--;
|
|
18576
|
+
if (depth === 0)
|
|
18577
|
+
return text.slice(openParen + 1, i2);
|
|
18578
|
+
}
|
|
18579
|
+
}
|
|
18580
|
+
return null;
|
|
18581
|
+
}
|
|
18582
|
+
function sanitizerCallRefs(sanitizers, sinkType) {
|
|
18583
|
+
const refs = [];
|
|
18584
|
+
for (const san of sanitizers) {
|
|
18585
|
+
if (!sanitizerCoversSink(san, sinkType))
|
|
18586
|
+
continue;
|
|
18587
|
+
const m = /(?:(\w+)\.)?(\w+)\(\)/.exec(san.method);
|
|
18588
|
+
if (!m?.[2])
|
|
18589
|
+
continue;
|
|
18590
|
+
refs.push({ receiver: m[1], methodName: m[2] });
|
|
18591
|
+
}
|
|
18592
|
+
return refs;
|
|
18593
|
+
}
|
|
18594
|
+
function maskSanitizerCalls(expr, refs) {
|
|
18595
|
+
let out2 = expr;
|
|
18596
|
+
for (const ref of refs) {
|
|
18597
|
+
const needles = ref.receiver ? [`${ref.receiver}.${ref.methodName}`, ref.methodName] : [ref.methodName];
|
|
18598
|
+
for (const needle of needles) {
|
|
18599
|
+
const re = new RegExp(`\\b${needle.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*\\(`);
|
|
18600
|
+
for (let guard = 0;guard < 8; guard++) {
|
|
18601
|
+
const m = re.exec(out2);
|
|
18602
|
+
if (!m)
|
|
18603
|
+
break;
|
|
18604
|
+
const open = m.index + m[0].length - 1;
|
|
18605
|
+
const arg = readBalancedArg(out2, open);
|
|
18606
|
+
if (arg === null)
|
|
18607
|
+
break;
|
|
18608
|
+
out2 = out2.slice(0, m.index) + " " + out2.slice(open + arg.length + 2);
|
|
18609
|
+
}
|
|
18610
|
+
}
|
|
18611
|
+
}
|
|
18612
|
+
return out2;
|
|
18613
|
+
}
|
|
18614
|
+
function blankStringLiterals(expr) {
|
|
18615
|
+
return expr.replace(/"(?:[^"\\]|\\.)*"/g, '""').replace(/'(?:[^'\\]|\\.)*'/g, "''");
|
|
18616
|
+
}
|
|
18617
|
+
function identifierOutsideSanitizerCalls(variable, calls, sanitizers, sinkType) {
|
|
18618
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(variable))
|
|
18619
|
+
return false;
|
|
18620
|
+
const refs = sanitizerCallRefs(sanitizers, sinkType);
|
|
18621
|
+
if (refs.length === 0)
|
|
18622
|
+
return false;
|
|
18623
|
+
const re = new RegExp(`(?:^|[^A-Za-z0-9_$])${variable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:[^A-Za-z0-9_$]|$)`);
|
|
18624
|
+
for (const call of calls) {
|
|
18625
|
+
if (refs.some((r) => r.methodName === call.method_name))
|
|
18626
|
+
continue;
|
|
18627
|
+
for (const arg of call.arguments) {
|
|
18628
|
+
const expr = arg.expression ?? "";
|
|
18629
|
+
if (!expr)
|
|
18630
|
+
continue;
|
|
18631
|
+
const masked = maskSanitizerCalls(expr, refs);
|
|
18632
|
+
if (masked === expr)
|
|
18633
|
+
continue;
|
|
18634
|
+
if (re.test(blankStringLiterals(masked)))
|
|
18635
|
+
return true;
|
|
18636
|
+
}
|
|
18637
|
+
}
|
|
18638
|
+
return false;
|
|
18639
|
+
}
|
|
18523
18640
|
function checkSanitized(fromLine, toLine, sinkType, sanitizersByLine, ctx) {
|
|
18524
18641
|
const isKnownSinkType = KNOWN_SINK_TYPES.has(sinkType);
|
|
18525
18642
|
const sanitizersAtTarget = sanitizersByLine.get(toLine);
|
|
@@ -24440,6 +24557,22 @@ class GoPlugin extends BaseLanguagePlugin {
|
|
|
24440
24557
|
confidence: 0.9,
|
|
24441
24558
|
returnTainted: true
|
|
24442
24559
|
},
|
|
24560
|
+
{
|
|
24561
|
+
method: "Get",
|
|
24562
|
+
class: "RequestPostForm",
|
|
24563
|
+
type: "http_body",
|
|
24564
|
+
severity: "high",
|
|
24565
|
+
confidence: 0.9,
|
|
24566
|
+
returnTainted: true
|
|
24567
|
+
},
|
|
24568
|
+
{
|
|
24569
|
+
method: "Get",
|
|
24570
|
+
class: "RequestForm",
|
|
24571
|
+
type: "http_param",
|
|
24572
|
+
severity: "high",
|
|
24573
|
+
confidence: 0.9,
|
|
24574
|
+
returnTainted: true
|
|
24575
|
+
},
|
|
24443
24576
|
{
|
|
24444
24577
|
method: "GetRawData",
|
|
24445
24578
|
class: "Context",
|
|
@@ -26338,6 +26471,7 @@ class LanguageSourcesPass {
|
|
|
26338
26471
|
additionalSources.push(...findGoMultipartUploadSources(code, language));
|
|
26339
26472
|
additionalSources.push(...findGoGrpcRequestSources(code, language));
|
|
26340
26473
|
additionalSources.push(...findGoRequestBodySources(code, language));
|
|
26474
|
+
additionalSources.push(...findGoFormIndexSources(code, language));
|
|
26341
26475
|
const jsDOMSinks = findJavaScriptDOMSinks(code, language);
|
|
26342
26476
|
for (const s of jsDOMSinks) {
|
|
26343
26477
|
const alreadyExists = additionalSinks.some((x) => x.line === s.line && x.cwe === s.cwe);
|
|
@@ -27144,6 +27278,48 @@ function findGoGrpcRequestSources(sourceCode, language) {
|
|
|
27144
27278
|
}
|
|
27145
27279
|
return sources;
|
|
27146
27280
|
}
|
|
27281
|
+
function findGoFormIndexSources(sourceCode, language) {
|
|
27282
|
+
if (language !== "go")
|
|
27283
|
+
return [];
|
|
27284
|
+
if (!/\.(?:PostForm|Form|MultipartForm)\b/.test(sourceCode))
|
|
27285
|
+
return [];
|
|
27286
|
+
const lines = sourceCode.split(`
|
|
27287
|
+
`);
|
|
27288
|
+
const reqNames = new Set;
|
|
27289
|
+
const paramRe = /([A-Za-z_]\w*)\s+\*http\.Request\b/g;
|
|
27290
|
+
for (const line of lines) {
|
|
27291
|
+
let m;
|
|
27292
|
+
paramRe.lastIndex = 0;
|
|
27293
|
+
while ((m = paramRe.exec(line)) !== null)
|
|
27294
|
+
reqNames.add(m[1]);
|
|
27295
|
+
}
|
|
27296
|
+
if (reqNames.size === 0)
|
|
27297
|
+
return [];
|
|
27298
|
+
const alt = [...reqNames].map((n) => n.replace(/\$/g, "\\$")).join("|");
|
|
27299
|
+
const indexRe = new RegExp(`^\\s*(?:var\\s+)?([A-Za-z_]\\w*)\\s*(?:,\\s*\\w+\\s*)?:?=\\s*(?:${alt})\\s*\\.\\s*(?:(PostForm|Form)|MultipartForm\\s*\\.\\s*Value)\\s*\\[`);
|
|
27300
|
+
const sources = [];
|
|
27301
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
27302
|
+
const line = lines[i2];
|
|
27303
|
+
if (/^\s*\/\//.test(line))
|
|
27304
|
+
continue;
|
|
27305
|
+
const m = indexRe.exec(line);
|
|
27306
|
+
if (!m)
|
|
27307
|
+
continue;
|
|
27308
|
+
const variable = m[1];
|
|
27309
|
+
if (variable === "_" || variable === "")
|
|
27310
|
+
continue;
|
|
27311
|
+
const kind = m[2];
|
|
27312
|
+
sources.push({
|
|
27313
|
+
type: kind === "Form" ? "http_param" : "http_body",
|
|
27314
|
+
location: "HTTP request form index",
|
|
27315
|
+
severity: "high",
|
|
27316
|
+
line: i2 + 1,
|
|
27317
|
+
confidence: 0.9,
|
|
27318
|
+
variable
|
|
27319
|
+
});
|
|
27320
|
+
}
|
|
27321
|
+
return sources;
|
|
27322
|
+
}
|
|
27147
27323
|
function findGoRequestBodySources(sourceCode, language) {
|
|
27148
27324
|
if (language !== "go")
|
|
27149
27325
|
return [];
|
|
@@ -35353,7 +35529,7 @@ class SinkFilterPass {
|
|
|
35353
35529
|
let filtered = sinks.filter((sink) => !constProp.unreachableLines.has(sink.line));
|
|
35354
35530
|
filtered = filterCleanArraySinks(filtered, calls, constProp.taintedArrayElements, constProp.symbols);
|
|
35355
35531
|
filtered = filterCleanVariableSinks(filtered, calls, constProp.tainted, constProp.symbols, dfg, constProp.sanitizedVars, constProp.synchronizedLines, language);
|
|
35356
|
-
filtered = filterSanitizedSinks(filtered, sanitizers, calls);
|
|
35532
|
+
filtered = filterSanitizedSinks(filtered, sanitizers, calls, sources);
|
|
35357
35533
|
if (language === "python") {
|
|
35358
35534
|
const { pyTaintedVars, pySanitizedVars } = langSources;
|
|
35359
35535
|
const sourceLines = ctx.code.split(`
|
|
@@ -35423,8 +35599,13 @@ class SinkFilterPass {
|
|
|
35423
35599
|
if (sink.type !== "xss")
|
|
35424
35600
|
return true;
|
|
35425
35601
|
const sinkLineText = sourceLines[sink.line - 1] ?? "";
|
|
35426
|
-
if (JS_XSS_SANITIZERS.some((p) => p.test(sinkLineText)))
|
|
35427
|
-
|
|
35602
|
+
if (JS_XSS_SANITIZERS.some((p) => p.test(sinkLineText))) {
|
|
35603
|
+
const callsAtSink = callsByLine.get(sink.line) ?? [];
|
|
35604
|
+
const covering = sanitizers.filter((s) => s.line === sink.line && sanitizerCoversSink(s, sink.type));
|
|
35605
|
+
const rawOperand = sources.some((s) => !!s.variable && identifierOutsideSanitizerCalls(s.variable, callsAtSink, covering, sink.type));
|
|
35606
|
+
if (!rawOperand)
|
|
35607
|
+
return false;
|
|
35608
|
+
}
|
|
35428
35609
|
const assignmentMatch = sinkLineText.match(/\.(?:innerHTML|outerHTML)\s*=\s*(.+)/);
|
|
35429
35610
|
if (assignmentMatch) {
|
|
35430
35611
|
const rhs = assignmentMatch[1].trim().replace(/;$/, "").trim();
|
|
@@ -36642,9 +36823,14 @@ function filterCleanVariableSinks(sinks, calls, taintedVars, symbols, dfg, sanit
|
|
|
36642
36823
|
return true;
|
|
36643
36824
|
});
|
|
36644
36825
|
}
|
|
36645
|
-
function filterSanitizedSinks(sinks, sanitizers, calls) {
|
|
36826
|
+
function filterSanitizedSinks(sinks, sanitizers, calls, sources) {
|
|
36646
36827
|
if (!sanitizers || sanitizers.length === 0)
|
|
36647
36828
|
return sinks;
|
|
36829
|
+
const sourceVars = [];
|
|
36830
|
+
for (const source of sources ?? []) {
|
|
36831
|
+
if (source.variable && /^[A-Za-z_$][\w$]*$/.test(source.variable))
|
|
36832
|
+
sourceVars.push(source.variable);
|
|
36833
|
+
}
|
|
36648
36834
|
const sanitizersByLine = new Map;
|
|
36649
36835
|
for (const san of sanitizers) {
|
|
36650
36836
|
const existing = sanitizersByLine.get(san.line) ?? [];
|
|
@@ -36661,23 +36847,30 @@ function filterSanitizedSinks(sinks, sanitizers, calls) {
|
|
|
36661
36847
|
const lineSanitizers = sanitizersByLine.get(sink.line);
|
|
36662
36848
|
if (!lineSanitizers || lineSanitizers.length === 0)
|
|
36663
36849
|
return true;
|
|
36664
|
-
|
|
36665
|
-
|
|
36666
|
-
|
|
36667
|
-
|
|
36668
|
-
|
|
36669
|
-
|
|
36670
|
-
|
|
36671
|
-
|
|
36672
|
-
|
|
36673
|
-
|
|
36674
|
-
|
|
36675
|
-
|
|
36676
|
-
|
|
36677
|
-
|
|
36678
|
-
|
|
36679
|
-
|
|
36680
|
-
|
|
36850
|
+
const lineCalls = callsByLine.get(sink.line) ?? [];
|
|
36851
|
+
const covering = lineSanitizers.filter((san) => sanitizerCoversSink(san, sink.type));
|
|
36852
|
+
if (covering.length === 0)
|
|
36853
|
+
return true;
|
|
36854
|
+
for (const variable of sourceVars) {
|
|
36855
|
+
if (identifierOutsideSanitizerCalls(variable, lineCalls, covering, sink.type))
|
|
36856
|
+
return true;
|
|
36857
|
+
}
|
|
36858
|
+
for (const san of covering) {
|
|
36859
|
+
const sanMethodMatch = san.method.match(/(?:(\w+)\.)?(\w+)\(\)/);
|
|
36860
|
+
if (!sanMethodMatch)
|
|
36861
|
+
continue;
|
|
36862
|
+
const sanMethodName = sanMethodMatch[2];
|
|
36863
|
+
const sanClassName = sanMethodMatch[1];
|
|
36864
|
+
for (const call of lineCalls) {
|
|
36865
|
+
if (call.method_name === sanMethodName)
|
|
36866
|
+
continue;
|
|
36867
|
+
for (const arg of call.arguments) {
|
|
36868
|
+
const expr = arg.expression || "";
|
|
36869
|
+
if (sanClassName) {
|
|
36870
|
+
if (expr.includes(`${sanClassName}.${sanMethodName}(`))
|
|
36871
|
+
return false;
|
|
36872
|
+
} else if (expr.includes(`${sanMethodName}(`)) {
|
|
36873
|
+
return false;
|
|
36681
36874
|
}
|
|
36682
36875
|
}
|
|
36683
36876
|
}
|
|
@@ -38123,9 +38316,14 @@ class TaintPropagationPass {
|
|
|
38123
38316
|
const sansAtSink = sanitizersByLine.get(f.sink_line);
|
|
38124
38317
|
if (sansAtSink && sansAtSink.length > 0) {
|
|
38125
38318
|
for (const san of sansAtSink) {
|
|
38126
|
-
if (sanitizerCoversSink(san, f.sink_type))
|
|
38127
|
-
|
|
38319
|
+
if (!sanitizerCoversSink(san, f.sink_type))
|
|
38320
|
+
continue;
|
|
38321
|
+
const sinkVar2 = f.path.length > 0 ? f.path[f.path.length - 1].variable : undefined;
|
|
38322
|
+
const callsAtSink = graph.callsByLine.get(f.sink_line) ?? [];
|
|
38323
|
+
if (sinkVar2 && identifierOutsideSanitizerCalls(sinkVar2, callsAtSink, sansAtSink, f.sink_type)) {
|
|
38324
|
+
continue;
|
|
38128
38325
|
}
|
|
38326
|
+
return false;
|
|
38129
38327
|
}
|
|
38130
38328
|
}
|
|
38131
38329
|
const usesAtSink = graph.usesByLine.get(f.sink_line);
|
|
@@ -40606,10 +40804,15 @@ class InterproceduralPass {
|
|
|
40606
40804
|
const sansAtSink = sanitizersByLine.get(f.sink_line);
|
|
40607
40805
|
if (!sansAtSink || sansAtSink.length === 0)
|
|
40608
40806
|
return true;
|
|
40807
|
+
const callsAtSink = graph.callsByLine.get(f.sink_line) ?? [];
|
|
40808
|
+
const sinkVar = f.path.length > 0 ? f.path[f.path.length - 1]?.variable : undefined;
|
|
40609
40809
|
for (const san of sansAtSink) {
|
|
40610
|
-
if (sanitizerCoversSink(san, f.sink_type))
|
|
40611
|
-
|
|
40810
|
+
if (!sanitizerCoversSink(san, f.sink_type))
|
|
40811
|
+
continue;
|
|
40812
|
+
if (sinkVar && identifierOutsideSanitizerCalls(sinkVar, callsAtSink, sansAtSink, f.sink_type)) {
|
|
40813
|
+
continue;
|
|
40612
40814
|
}
|
|
40815
|
+
return false;
|
|
40613
40816
|
}
|
|
40614
40817
|
return true;
|
|
40615
40818
|
});
|
|
@@ -45045,6 +45248,13 @@ var PROVIDER_PATTERNS = [
|
|
|
45045
45248
|
level: "error",
|
|
45046
45249
|
fix: "Revoke the GitHub refresh token and store secrets outside source control."
|
|
45047
45250
|
},
|
|
45251
|
+
{
|
|
45252
|
+
name: "GitHub fine-grained personal access token",
|
|
45253
|
+
regex: /\bgithub_pat_[A-Za-z0-9]{22}_[A-Za-z0-9]{59}\b/,
|
|
45254
|
+
severity: "critical",
|
|
45255
|
+
level: "error",
|
|
45256
|
+
fix: "Revoke the fine-grained personal access token at https://github.com/settings/tokens and store secrets outside source control."
|
|
45257
|
+
},
|
|
45048
45258
|
{
|
|
45049
45259
|
name: "GitLab personal access token",
|
|
45050
45260
|
regex: /\bglpat-[A-Za-z0-9_-]{20,}\b/,
|
|
@@ -45069,9 +45279,9 @@ var PROVIDER_PATTERNS = [
|
|
|
45069
45279
|
{
|
|
45070
45280
|
name: "Stripe live publishable key",
|
|
45071
45281
|
regex: /\bpk_live_[A-Za-z0-9]{24,}\b/,
|
|
45072
|
-
severity: "
|
|
45073
|
-
level: "
|
|
45074
|
-
fix: "Publishable keys are not secret
|
|
45282
|
+
severity: "low",
|
|
45283
|
+
level: "note",
|
|
45284
|
+
fix: "Publishable keys are not secret. Prefer loading them from configuration rather than a backend source file."
|
|
45075
45285
|
},
|
|
45076
45286
|
{
|
|
45077
45287
|
name: "Stripe test secret key",
|
|
@@ -45094,6 +45304,13 @@ var PROVIDER_PATTERNS = [
|
|
|
45094
45304
|
level: "error",
|
|
45095
45305
|
fix: "Revoke the OpenAI key at https://platform.openai.com/api-keys and load from environment."
|
|
45096
45306
|
},
|
|
45307
|
+
{
|
|
45308
|
+
name: "OpenAI project API key",
|
|
45309
|
+
regex: /\bsk-proj-[A-Za-z0-9_-]{48,}\b/,
|
|
45310
|
+
severity: "critical",
|
|
45311
|
+
level: "error",
|
|
45312
|
+
fix: "Revoke the OpenAI project key at https://platform.openai.com/api-keys and load from environment."
|
|
45313
|
+
},
|
|
45097
45314
|
{
|
|
45098
45315
|
name: "Anthropic API key",
|
|
45099
45316
|
regex: /\bsk-ant-[A-Za-z0-9_-]{90,}\b/,
|
|
@@ -45431,7 +45648,7 @@ class ScanSecretsPass {
|
|
|
45431
45648
|
const m = pattern.regex.exec(lineText);
|
|
45432
45649
|
if (!m)
|
|
45433
45650
|
continue;
|
|
45434
|
-
if ((pattern.name === "Stripe live restricted key" || pattern.name === "Stripe test secret key" || pattern.name === "Stripe test restricted key" || pattern.name === "GitLab personal access token") && PLACEHOLDER_RE.test(m[0])) {
|
|
45651
|
+
if ((pattern.name === "Stripe live restricted key" || pattern.name === "Stripe test secret key" || pattern.name === "Stripe test restricted key" || pattern.name === "GitLab personal access token" || pattern.name === "OpenAI project API key" || pattern.name === "GitHub fine-grained personal access token") && PLACEHOLDER_RE.test(m[0])) {
|
|
45435
45652
|
continue;
|
|
45436
45653
|
}
|
|
45437
45654
|
if (pattern.name === "PEM private key" && !pemHasInlineBody(lines, i2)) {
|
|
@@ -45867,8 +46084,6 @@ var PY_SET_COOKIE_RECEIVERS = new Set([
|
|
|
45867
46084
|
]);
|
|
45868
46085
|
var PY_SECURE_TRUE_RE = /\bsecure\s*=\s*True\b/;
|
|
45869
46086
|
var PY_HTTPONLY_TRUE_RE = /\bhttponly\s*=\s*True\b/i;
|
|
45870
|
-
var JAVA_SET_SECURE_TRUE_RE = /\.setSecure\s*\(\s*true\s*\)/;
|
|
45871
|
-
var JAVA_SET_HTTPONLY_TRUE_RE = /\.setHttpOnly\s*\(\s*true\s*\)/;
|
|
45872
46087
|
var GO_SECURE_TRUE_RE = /\bSecure\s*:\s*true\b/;
|
|
45873
46088
|
var GO_HTTPONLY_TRUE_RE = /\bHttpOnly\s*:\s*true\b/;
|
|
45874
46089
|
var RUST_SET_COOKIE_MACRO_RE = /(format!|write!|writeln!)\s*\(([^()]*Set-Cookie[^()]*)\)/gis;
|
|
@@ -45900,10 +46115,8 @@ class InsecureCookiePass {
|
|
|
45900
46115
|
this.emit(ctx, file, det, "python");
|
|
45901
46116
|
}
|
|
45902
46117
|
} else if (language === "java") {
|
|
45903
|
-
const hasSetSecureTrue = JAVA_SET_SECURE_TRUE_RE.test(code);
|
|
45904
|
-
const hasSetHttpOnlyTrue = JAVA_SET_HTTPONLY_TRUE_RE.test(code);
|
|
45905
46118
|
for (const call of graph.ir.calls) {
|
|
45906
|
-
const det = this.detectJavaCookieCtor(call,
|
|
46119
|
+
const det = this.detectJavaCookieCtor(call, code);
|
|
45907
46120
|
if (!det)
|
|
45908
46121
|
continue;
|
|
45909
46122
|
insecureCookies.push(det);
|
|
@@ -45989,7 +46202,15 @@ class InsecureCookiePass {
|
|
|
45989
46202
|
optionsPresent: call.arguments.length >= 2
|
|
45990
46203
|
};
|
|
45991
46204
|
}
|
|
45992
|
-
|
|
46205
|
+
javaCookieSetterTrue(code, call, setter) {
|
|
46206
|
+
const line = code.split(`
|
|
46207
|
+
`)[(call.location.line ?? 1) - 1] ?? "";
|
|
46208
|
+
const assign = /\b([A-Za-z_]\w*)\s*=\s*new\s+(?:[\w.]+\.)?Cookie\b/.exec(line);
|
|
46209
|
+
const varName = assign?.[1];
|
|
46210
|
+
const re = varName ? new RegExp(`\\b${varName}\\.${setter}\\s*\\(\\s*true\\s*\\)`) : new RegExp(`\\.${setter}\\s*\\(\\s*true\\s*\\)`);
|
|
46211
|
+
return re.test(varName ? code : line);
|
|
46212
|
+
}
|
|
46213
|
+
detectJavaCookieCtor(call, code) {
|
|
45993
46214
|
const method = call.method_name ?? "";
|
|
45994
46215
|
const isCookieCtor = method === "Cookie" || method.endsWith(".Cookie");
|
|
45995
46216
|
if (!isCookieCtor)
|
|
@@ -45999,8 +46220,8 @@ class InsecureCookiePass {
|
|
|
45999
46220
|
return null;
|
|
46000
46221
|
if (call.arguments.length < 2)
|
|
46001
46222
|
return null;
|
|
46002
|
-
const missingSecure = !
|
|
46003
|
-
const missingHttpOnly = !
|
|
46223
|
+
const missingSecure = !this.javaCookieSetterTrue(code, call, "setSecure");
|
|
46224
|
+
const missingHttpOnly = !this.javaCookieSetterTrue(code, call, "setHttpOnly");
|
|
46004
46225
|
if (!missingSecure && !missingHttpOnly)
|
|
46005
46226
|
return null;
|
|
46006
46227
|
return {
|
|
@@ -52155,7 +52376,7 @@ var colors = {
|
|
|
52155
52376
|
};
|
|
52156
52377
|
|
|
52157
52378
|
// src/version.ts
|
|
52158
|
-
var version = "4.14.
|
|
52379
|
+
var version = "4.14.2";
|
|
52159
52380
|
|
|
52160
52381
|
// src/formatters.ts
|
|
52161
52382
|
var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
|
|
@@ -52722,8 +52943,8 @@ function generateSarifResults(results, crossFileData) {
|
|
|
52722
52943
|
|
|
52723
52944
|
// src/build-info.ts
|
|
52724
52945
|
var buildInfo = {
|
|
52725
|
-
gitSha: "
|
|
52726
|
-
builtAt: "2026-10-
|
|
52946
|
+
gitSha: "b1967eb",
|
|
52947
|
+
builtAt: "2026-10-13T06:43:43.278Z"
|
|
52727
52948
|
};
|
|
52728
52949
|
|
|
52729
52950
|
// src/utils/args.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "4.14.
|
|
3
|
+
"version": "4.14.2",
|
|
4
4
|
"description": "Static Application Security Testing CLI for detecting security vulnerabilities via taint tracking",
|
|
5
5
|
"bin": {
|
|
6
6
|
"cognium-dev": "dist/cli.js"
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"@cognium/project-profile-detect": "1.1.2",
|
|
68
|
-
"circle-ir": "4.14.
|
|
68
|
+
"circle-ir": "4.14.2"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/node": "^26.6.4",
|