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.
- package/dist/cli.js +328 -11
- 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
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
68
|
+
"circle-ir": "^3.105.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/node": "^25.5.0",
|