cognium-dev 3.126.0 → 3.129.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 +451 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -22600,6 +22600,10 @@ class LanguageSourcesPass {
|
|
|
22600
22600
|
if (language === "go") {
|
|
22601
22601
|
additionalSanitizers.push(...findGoMapAllowlistGuardSanitizers(code));
|
|
22602
22602
|
additionalSanitizers.push(...findGoHtmlTemplateImportSanitizers(code));
|
|
22603
|
+
const goMisconfigFindings = findGoPatternFindings(code, graph.ir.meta.file);
|
|
22604
|
+
for (const finding of goMisconfigFindings) {
|
|
22605
|
+
ctx.addFinding(finding);
|
|
22606
|
+
}
|
|
22603
22607
|
}
|
|
22604
22608
|
if (language === "python") {
|
|
22605
22609
|
additionalSanitizers.push(...findPythonNetlocAllowlistGuardSanitizers(code));
|
|
@@ -22607,6 +22611,7 @@ class LanguageSourcesPass {
|
|
|
22607
22611
|
additionalSanitizers.push(...findPythonRegexAllowlistWrapperSanitizers(code));
|
|
22608
22612
|
additionalSanitizers.push(...findPythonSetMembershipXssGuardSanitizers(code));
|
|
22609
22613
|
additionalSanitizers.push(...findPythonDefusedXmlSanitizers(code));
|
|
22614
|
+
additionalSanitizers.push(...findPythonJinjaAutoescapeSanitizers(code));
|
|
22610
22615
|
const pyMisconfigFindings = findPythonPatternFindings(code, graph.ir.meta.file);
|
|
22611
22616
|
for (const finding of pyMisconfigFindings) {
|
|
22612
22617
|
ctx.addFinding(finding);
|
|
@@ -22615,10 +22620,23 @@ class LanguageSourcesPass {
|
|
|
22615
22620
|
if (language === "rust") {
|
|
22616
22621
|
additionalSanitizers.push(...findRustSetAllowlistGuardSanitizers(code));
|
|
22617
22622
|
additionalSanitizers.push(...findRustCanonicalizeGuardSanitizers(code));
|
|
22623
|
+
additionalSanitizers.push(...findRustArgvCommandSanitizers(code));
|
|
22618
22624
|
const rustMisconfigFindings = findRustPatternFindings(code, graph.ir.meta.file);
|
|
22619
22625
|
for (const finding of rustMisconfigFindings) {
|
|
22620
22626
|
ctx.addFinding(finding);
|
|
22621
22627
|
}
|
|
22628
|
+
for (const finding of findRustHardcodedCredentialFindings(code, graph.ir.meta.file)) {
|
|
22629
|
+
ctx.addFinding(finding);
|
|
22630
|
+
}
|
|
22631
|
+
for (const finding of findRustInsecureCookieFindings(code, graph.ir.meta.file)) {
|
|
22632
|
+
ctx.addFinding(finding);
|
|
22633
|
+
}
|
|
22634
|
+
for (const finding of findRustJwtVerifyDisabledFindings(code, graph.ir.meta.file)) {
|
|
22635
|
+
ctx.addFinding(finding);
|
|
22636
|
+
}
|
|
22637
|
+
for (const finding of findRustWeakCryptoEcbFindings(code, graph.ir.meta.file)) {
|
|
22638
|
+
ctx.addFinding(finding);
|
|
22639
|
+
}
|
|
22622
22640
|
}
|
|
22623
22641
|
if (language === "javascript" || language === "typescript" || language === "htmljs") {
|
|
22624
22642
|
additionalSanitizers.push(...findJsSafeJsonParseSanitizers(code));
|
|
@@ -22626,9 +22644,18 @@ class LanguageSourcesPass {
|
|
|
22626
22644
|
additionalSanitizers.push(...findJsCsvFormulaPrefixSanitizers(code));
|
|
22627
22645
|
additionalSanitizers.push(...findJsWrapperFunctionSanitizers(code));
|
|
22628
22646
|
additionalSanitizers.push(...findJsSsrfAllowlistGuardSanitizers(code));
|
|
22647
|
+
for (const finding of findJsPatternFindings(code, graph.ir.meta.file)) {
|
|
22648
|
+
ctx.addFinding(finding);
|
|
22649
|
+
}
|
|
22629
22650
|
}
|
|
22630
22651
|
if (language === "java") {
|
|
22631
22652
|
additionalSanitizers.push(...findJavaSafeJsonParseSanitizers(code));
|
|
22653
|
+
additionalSanitizers.push(...findJavaPathNormalizeStartsWithGuardSanitizers(code));
|
|
22654
|
+
additionalSanitizers.push(...findJavaInlineCrlfStripLogSanitizers(code));
|
|
22655
|
+
additionalSanitizers.push(...findJavaArgvFormExecSanitizers(code));
|
|
22656
|
+
for (const finding of findJavaPatternFindings(code, graph.ir.meta.file)) {
|
|
22657
|
+
ctx.addFinding(finding);
|
|
22658
|
+
}
|
|
22632
22659
|
}
|
|
22633
22660
|
if (language === "python" || language === "javascript" || language === "typescript" || language === "go") {
|
|
22634
22661
|
const exfilFindings = findExternalSecretExfiltrationFindings(code, graph.ir.meta.file, language);
|
|
@@ -24580,6 +24607,152 @@ function findJsSsrfAllowlistGuardSanitizers(code) {
|
|
|
24580
24607
|
}
|
|
24581
24608
|
return sanitizers;
|
|
24582
24609
|
}
|
|
24610
|
+
function findJavaPathNormalizeStartsWithGuardSanitizers(code) {
|
|
24611
|
+
const sanitizers = [];
|
|
24612
|
+
const lines = code.split(`
|
|
24613
|
+
`);
|
|
24614
|
+
const resolveNormalizeRe = /\b([A-Za-z_]\w*)\s*=\s*([A-Za-z_]\w*)\s*\.\s*resolve\s*\([^)]*\)\s*\.\s*normalize\s*\(\s*\)/;
|
|
24615
|
+
const startsWithGuardRe = (varName, rootName) => new RegExp(`if\\s*\\(\\s*!\\s*${varName}\\s*\\.\\s*startsWith\\s*\\(\\s*${rootName}\\s*\\)\\s*\\)`);
|
|
24616
|
+
const terminatorRe = /\b(throw|return)\b/;
|
|
24617
|
+
const candidates = [];
|
|
24618
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24619
|
+
const m = resolveNormalizeRe.exec(lines[i2]);
|
|
24620
|
+
if (!m)
|
|
24621
|
+
continue;
|
|
24622
|
+
candidates.push({ line: i2 + 1, fullVar: m[1], rootVar: m[2] });
|
|
24623
|
+
}
|
|
24624
|
+
if (candidates.length === 0)
|
|
24625
|
+
return sanitizers;
|
|
24626
|
+
for (const c of candidates) {
|
|
24627
|
+
const guardRe = startsWithGuardRe(c.fullVar, c.rootVar);
|
|
24628
|
+
let guardLine = -1;
|
|
24629
|
+
for (let l = c.line;l < Math.min(lines.length, c.line + 6); l++) {
|
|
24630
|
+
if (!guardRe.test(lines[l]))
|
|
24631
|
+
continue;
|
|
24632
|
+
if (terminatorRe.test(lines[l]) || l + 1 < lines.length && terminatorRe.test(lines[l + 1])) {
|
|
24633
|
+
guardLine = l + 1;
|
|
24634
|
+
break;
|
|
24635
|
+
}
|
|
24636
|
+
}
|
|
24637
|
+
if (guardLine < 0)
|
|
24638
|
+
continue;
|
|
24639
|
+
const varRefRe = new RegExp(`\\b${c.fullVar}\\b`);
|
|
24640
|
+
sanitizers.push({
|
|
24641
|
+
type: "java_path_normalize_startswith_guard",
|
|
24642
|
+
method: "normalize",
|
|
24643
|
+
line: c.line,
|
|
24644
|
+
sanitizes: ["path_traversal", "external_taint_escape"]
|
|
24645
|
+
});
|
|
24646
|
+
for (let l = c.line;l < lines.length; l++) {
|
|
24647
|
+
if (!varRefRe.test(lines[l]))
|
|
24648
|
+
continue;
|
|
24649
|
+
sanitizers.push({
|
|
24650
|
+
type: "java_path_normalize_startswith_guard",
|
|
24651
|
+
method: "normalize",
|
|
24652
|
+
line: l + 1,
|
|
24653
|
+
sanitizes: ["path_traversal", "external_taint_escape"]
|
|
24654
|
+
});
|
|
24655
|
+
}
|
|
24656
|
+
}
|
|
24657
|
+
return sanitizers;
|
|
24658
|
+
}
|
|
24659
|
+
function findJavaInlineCrlfStripLogSanitizers(code) {
|
|
24660
|
+
const sanitizers = [];
|
|
24661
|
+
const lines = code.split(`
|
|
24662
|
+
`);
|
|
24663
|
+
const logCallStart = /\b(?:log|logger|LOG|LOGGER|slog|LOGGER_)\s*\.\s*(?:info|warn|error|debug|trace|fatal|severe|warning|fine|finer|finest|config)\s*\(/;
|
|
24664
|
+
const crlfReplaceAll = /\.\s*replaceAll\s*\(\s*"\[[^"]*\\\\?[rnt][^"]*\]"/;
|
|
24665
|
+
const crlfReplaceChar = /\.\s*replace\s*\(\s*'(?:\\\\?[rnt])'\s*,/;
|
|
24666
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24667
|
+
const text = lines[i2];
|
|
24668
|
+
if (!logCallStart.test(text))
|
|
24669
|
+
continue;
|
|
24670
|
+
if (!crlfReplaceAll.test(text) && !crlfReplaceChar.test(text))
|
|
24671
|
+
continue;
|
|
24672
|
+
sanitizers.push({
|
|
24673
|
+
type: "java_inline_crlf_strip_log",
|
|
24674
|
+
method: "replaceAll",
|
|
24675
|
+
line: i2 + 1,
|
|
24676
|
+
sanitizes: ["log_injection", "external_taint_escape"]
|
|
24677
|
+
});
|
|
24678
|
+
}
|
|
24679
|
+
return sanitizers;
|
|
24680
|
+
}
|
|
24681
|
+
function findJavaArgvFormExecSanitizers(code) {
|
|
24682
|
+
const sanitizers = [];
|
|
24683
|
+
const lines = code.split(`
|
|
24684
|
+
`);
|
|
24685
|
+
const argvExecRe = /\.\s*exec\s*\(\s*new\s+String\s*\[\s*\]\s*\{/;
|
|
24686
|
+
const argvPbRe = /\bnew\s+ProcessBuilder\s*\(\s*new\s+String\s*\[\s*\]\s*\{/;
|
|
24687
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24688
|
+
const text = lines[i2];
|
|
24689
|
+
if (!argvExecRe.test(text) && !argvPbRe.test(text))
|
|
24690
|
+
continue;
|
|
24691
|
+
sanitizers.push({
|
|
24692
|
+
type: "java_argv_form_exec",
|
|
24693
|
+
method: "exec",
|
|
24694
|
+
line: i2 + 1,
|
|
24695
|
+
sanitizes: ["command_injection", "external_taint_escape"]
|
|
24696
|
+
});
|
|
24697
|
+
}
|
|
24698
|
+
return sanitizers;
|
|
24699
|
+
}
|
|
24700
|
+
function findRustArgvCommandSanitizers(code) {
|
|
24701
|
+
const sanitizers = [];
|
|
24702
|
+
const lines = code.split(`
|
|
24703
|
+
`);
|
|
24704
|
+
const argvCommandRe = /\bCommand\s*::\s*new\s*\(\s*"[^"]*"\s*\)\s*\.\s*arg\s*\(/;
|
|
24705
|
+
const shellArgvRe = /\bCommand\s*::\s*new\s*\(\s*"(?:sh|bash|zsh|ksh|dash|cmd(?:\.exe)?|powershell|pwsh)"\s*\)\s*\.\s*arg\s*\(\s*"-c"/;
|
|
24706
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24707
|
+
const text = lines[i2];
|
|
24708
|
+
if (!argvCommandRe.test(text))
|
|
24709
|
+
continue;
|
|
24710
|
+
if (shellArgvRe.test(text))
|
|
24711
|
+
continue;
|
|
24712
|
+
sanitizers.push({
|
|
24713
|
+
type: "rust_argv_command",
|
|
24714
|
+
method: "arg",
|
|
24715
|
+
line: i2 + 1,
|
|
24716
|
+
sanitizes: ["command_injection", "external_taint_escape"]
|
|
24717
|
+
});
|
|
24718
|
+
}
|
|
24719
|
+
return sanitizers;
|
|
24720
|
+
}
|
|
24721
|
+
function findPythonJinjaAutoescapeSanitizers(code) {
|
|
24722
|
+
const sanitizers = [];
|
|
24723
|
+
const lines = code.split(`
|
|
24724
|
+
`);
|
|
24725
|
+
const envAssignRe = /\b([A-Za-z_]\w*)\s*=\s*Environment\s*\(/;
|
|
24726
|
+
const autoescapeOnRe = /\bautoescape\s*=/;
|
|
24727
|
+
const autoescapeOffRe = /\bautoescape\s*=\s*(?:False|None|0)\b/;
|
|
24728
|
+
const envVars = new Set;
|
|
24729
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24730
|
+
const m = envAssignRe.exec(lines[i2]);
|
|
24731
|
+
if (!m)
|
|
24732
|
+
continue;
|
|
24733
|
+
if (!autoescapeOnRe.test(lines[i2]))
|
|
24734
|
+
continue;
|
|
24735
|
+
if (autoescapeOffRe.test(lines[i2]))
|
|
24736
|
+
continue;
|
|
24737
|
+
envVars.add(m[1]);
|
|
24738
|
+
}
|
|
24739
|
+
if (envVars.size === 0)
|
|
24740
|
+
return sanitizers;
|
|
24741
|
+
for (const envVar of envVars) {
|
|
24742
|
+
const renderChainRe = new RegExp(`\\b${envVar}\\s*\\.\\s*get_template\\s*\\([^)]*\\)\\s*\\.\\s*render\\s*\\(`);
|
|
24743
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24744
|
+
if (!renderChainRe.test(lines[i2]))
|
|
24745
|
+
continue;
|
|
24746
|
+
sanitizers.push({
|
|
24747
|
+
type: "python_jinja_autoescape",
|
|
24748
|
+
method: "render",
|
|
24749
|
+
line: i2 + 1,
|
|
24750
|
+
sanitizes: ["xss", "external_taint_escape"]
|
|
24751
|
+
});
|
|
24752
|
+
}
|
|
24753
|
+
}
|
|
24754
|
+
return sanitizers;
|
|
24755
|
+
}
|
|
24583
24756
|
function collectEnvSecretVars(lines, language) {
|
|
24584
24757
|
const out2 = new Map;
|
|
24585
24758
|
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
@@ -24994,6 +25167,283 @@ function findRustPatternFindings(code, file) {
|
|
|
24994
25167
|
}
|
|
24995
25168
|
return out2;
|
|
24996
25169
|
}
|
|
25170
|
+
function findRustHardcodedCredentialFindings(code, file) {
|
|
25171
|
+
const out2 = [];
|
|
25172
|
+
const lines = code.split(`
|
|
25173
|
+
`);
|
|
25174
|
+
const re = /\b(?:pub\s+)?(?:const|static)\s+([A-Z][A-Z0-9_]*)\s*:\s*&\s*'?[a-z_]*\s*str\s*=\s*"([^"]+)"/;
|
|
25175
|
+
const nameRe = /(?:^|_)(?:API[_]?KEY|SECRET|TOKEN|PASSWORD|PASSWD|PWD|AUTH)(?:_|$)/i;
|
|
25176
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
25177
|
+
const raw = lines[i2];
|
|
25178
|
+
const trimmed = raw.trim();
|
|
25179
|
+
if (!trimmed || trimmed.startsWith("//"))
|
|
25180
|
+
continue;
|
|
25181
|
+
const m = trimmed.match(re);
|
|
25182
|
+
if (!m)
|
|
25183
|
+
continue;
|
|
25184
|
+
const name2 = m[1];
|
|
25185
|
+
const value = m[2];
|
|
25186
|
+
if (!nameRe.test(name2))
|
|
25187
|
+
continue;
|
|
25188
|
+
if (value.length < 8)
|
|
25189
|
+
continue;
|
|
25190
|
+
if (/^(?:xxx|todo|fixme|placeholder|changeme)/i.test(value))
|
|
25191
|
+
continue;
|
|
25192
|
+
out2.push({
|
|
25193
|
+
id: `hardcoded-credential-${file}-${i2 + 1}`,
|
|
25194
|
+
pass: "language-sources",
|
|
25195
|
+
category: "security",
|
|
25196
|
+
rule_id: "hardcoded-credential",
|
|
25197
|
+
cwe: "CWE-798",
|
|
25198
|
+
severity: "high",
|
|
25199
|
+
level: "error",
|
|
25200
|
+
message: `Hardcoded credential: const ${name2} contains a literal secret value`,
|
|
25201
|
+
file,
|
|
25202
|
+
line: i2 + 1,
|
|
25203
|
+
snippet: trimmed.substring(0, 100)
|
|
25204
|
+
});
|
|
25205
|
+
}
|
|
25206
|
+
return out2;
|
|
25207
|
+
}
|
|
25208
|
+
function findRustInsecureCookieFindings(code, file) {
|
|
25209
|
+
const out2 = [];
|
|
25210
|
+
const lines = code.split(`
|
|
25211
|
+
`);
|
|
25212
|
+
const builderRe = /\bCookie\s*::\s*build\s*\(/;
|
|
25213
|
+
const insecureFlagRe = /\.\s*(?:secure|http_only)\s*\(\s*false\s*\)/;
|
|
25214
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
25215
|
+
const raw = lines[i2];
|
|
25216
|
+
const trimmed = raw.trim();
|
|
25217
|
+
if (!trimmed || trimmed.startsWith("//"))
|
|
25218
|
+
continue;
|
|
25219
|
+
if (!builderRe.test(trimmed))
|
|
25220
|
+
continue;
|
|
25221
|
+
if (!insecureFlagRe.test(trimmed))
|
|
25222
|
+
continue;
|
|
25223
|
+
out2.push({
|
|
25224
|
+
id: `insecure-cookie-${file}-${i2 + 1}`,
|
|
25225
|
+
pass: "language-sources",
|
|
25226
|
+
category: "security",
|
|
25227
|
+
rule_id: "insecure-cookie",
|
|
25228
|
+
cwe: "CWE-1004",
|
|
25229
|
+
severity: "medium",
|
|
25230
|
+
level: "warning",
|
|
25231
|
+
message: "Insecure cookie: Cookie::build chain disables Secure / HttpOnly flag(s)",
|
|
25232
|
+
file,
|
|
25233
|
+
line: i2 + 1,
|
|
25234
|
+
snippet: trimmed.substring(0, 100)
|
|
25235
|
+
});
|
|
25236
|
+
}
|
|
25237
|
+
return out2;
|
|
25238
|
+
}
|
|
25239
|
+
function findRustJwtVerifyDisabledFindings(code, file) {
|
|
25240
|
+
const out2 = [];
|
|
25241
|
+
const lines = code.split(`
|
|
25242
|
+
`);
|
|
25243
|
+
const re = /\.\s*insecure_disable_signature_validation\s*\(/;
|
|
25244
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
25245
|
+
const raw = lines[i2];
|
|
25246
|
+
const trimmed = raw.trim();
|
|
25247
|
+
if (!trimmed || trimmed.startsWith("//"))
|
|
25248
|
+
continue;
|
|
25249
|
+
if (!re.test(trimmed))
|
|
25250
|
+
continue;
|
|
25251
|
+
out2.push({
|
|
25252
|
+
id: `jwt-verify-disabled-${file}-${i2 + 1}`,
|
|
25253
|
+
pass: "language-sources",
|
|
25254
|
+
category: "security",
|
|
25255
|
+
rule_id: "jwt-verify-disabled",
|
|
25256
|
+
cwe: "CWE-347",
|
|
25257
|
+
severity: "critical",
|
|
25258
|
+
level: "error",
|
|
25259
|
+
message: "JWT signature verification disabled: " + "Validation::insecure_disable_signature_validation() forfeits signature enforcement",
|
|
25260
|
+
file,
|
|
25261
|
+
line: i2 + 1,
|
|
25262
|
+
snippet: trimmed.substring(0, 100)
|
|
25263
|
+
});
|
|
25264
|
+
}
|
|
25265
|
+
return out2;
|
|
25266
|
+
}
|
|
25267
|
+
function findRustWeakCryptoEcbFindings(code, file) {
|
|
25268
|
+
const out2 = [];
|
|
25269
|
+
const lines = code.split(`
|
|
25270
|
+
`);
|
|
25271
|
+
const ctorRe = /\bAes(?:128|192|256)(?:Ecb)?\s*::\s*new\s*\(/;
|
|
25272
|
+
const blockOpRe = /\.\s*(encrypt_block|decrypt_block)\s*\(/;
|
|
25273
|
+
let sawCtor = false;
|
|
25274
|
+
for (const line of lines) {
|
|
25275
|
+
if (ctorRe.test(line)) {
|
|
25276
|
+
sawCtor = true;
|
|
25277
|
+
break;
|
|
25278
|
+
}
|
|
25279
|
+
}
|
|
25280
|
+
if (!sawCtor)
|
|
25281
|
+
return out2;
|
|
25282
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
25283
|
+
const raw = lines[i2];
|
|
25284
|
+
const trimmed = raw.trim();
|
|
25285
|
+
if (!trimmed || trimmed.startsWith("//"))
|
|
25286
|
+
continue;
|
|
25287
|
+
if (!blockOpRe.test(trimmed))
|
|
25288
|
+
continue;
|
|
25289
|
+
out2.push({
|
|
25290
|
+
id: `weak-crypto-${file}-${i2 + 1}`,
|
|
25291
|
+
pass: "language-sources",
|
|
25292
|
+
category: "security",
|
|
25293
|
+
rule_id: "weak-crypto",
|
|
25294
|
+
cwe: "CWE-327",
|
|
25295
|
+
severity: "high",
|
|
25296
|
+
level: "error",
|
|
25297
|
+
message: "Weak crypto (ECB mode): raw Aes::encrypt_block/decrypt_block " + "leaks repeating-block patterns. Use AES-GCM, AES-CTR, or " + "AES-CBC with an HMAC.",
|
|
25298
|
+
file,
|
|
25299
|
+
line: i2 + 1,
|
|
25300
|
+
snippet: trimmed.substring(0, 100)
|
|
25301
|
+
});
|
|
25302
|
+
}
|
|
25303
|
+
return out2;
|
|
25304
|
+
}
|
|
25305
|
+
function findJavaPatternFindings(code, file) {
|
|
25306
|
+
const out2 = [];
|
|
25307
|
+
const lines = code.split(`
|
|
25308
|
+
`);
|
|
25309
|
+
const jwtDecodeRe = /\bJWT\s*\.\s*decode\s*\(/;
|
|
25310
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
25311
|
+
const raw = lines[i2];
|
|
25312
|
+
const trimmed = raw.trim();
|
|
25313
|
+
if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("*"))
|
|
25314
|
+
continue;
|
|
25315
|
+
if (!jwtDecodeRe.test(trimmed))
|
|
25316
|
+
continue;
|
|
25317
|
+
if (/\.\s*verify\s*\(/.test(trimmed))
|
|
25318
|
+
continue;
|
|
25319
|
+
out2.push({
|
|
25320
|
+
id: `jwt-verify-disabled-${file}-${i2 + 1}-decode`,
|
|
25321
|
+
pass: "language-sources",
|
|
25322
|
+
category: "security",
|
|
25323
|
+
rule_id: "jwt-verify-disabled",
|
|
25324
|
+
cwe: "CWE-347",
|
|
25325
|
+
severity: "critical",
|
|
25326
|
+
level: "error",
|
|
25327
|
+
message: "JWT signature not verified: auth0 `JWT.decode(token)` parses " + "without checking the signature. Use `JWT.require(<algorithm>)" + ".build().verify(token)` to enforce verification.",
|
|
25328
|
+
file,
|
|
25329
|
+
line: i2 + 1,
|
|
25330
|
+
snippet: trimmed.substring(0, 100)
|
|
25331
|
+
});
|
|
25332
|
+
}
|
|
25333
|
+
const anonStartRe = /\bnew\s+X509TrustManager\s*\(\s*\)\s*\{/;
|
|
25334
|
+
const checkServerSig = /\bcheckServerTrusted\s*\([^)]*\)\s*(?:throws\s+[^\{]*)?\{\s*\}/;
|
|
25335
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
25336
|
+
const raw = lines[i2];
|
|
25337
|
+
if (!anonStartRe.test(raw))
|
|
25338
|
+
continue;
|
|
25339
|
+
const end = Math.min(lines.length, i2 + 16);
|
|
25340
|
+
let foundAt = -1;
|
|
25341
|
+
for (let j = i2;j < end; j++) {
|
|
25342
|
+
if (checkServerSig.test(lines[j])) {
|
|
25343
|
+
foundAt = j;
|
|
25344
|
+
break;
|
|
25345
|
+
}
|
|
25346
|
+
}
|
|
25347
|
+
if (foundAt < 0)
|
|
25348
|
+
continue;
|
|
25349
|
+
out2.push({
|
|
25350
|
+
id: `tls-verify-disabled-${file}-${foundAt + 1}`,
|
|
25351
|
+
pass: "language-sources",
|
|
25352
|
+
category: "security",
|
|
25353
|
+
rule_id: "tls-verify-disabled",
|
|
25354
|
+
cwe: "CWE-295",
|
|
25355
|
+
severity: "high",
|
|
25356
|
+
level: "error",
|
|
25357
|
+
message: "TLS certificate verification disabled: anonymous X509TrustManager " + "with empty checkServerTrusted body accepts every certificate.",
|
|
25358
|
+
file,
|
|
25359
|
+
line: foundAt + 1,
|
|
25360
|
+
snippet: lines[foundAt].trim().substring(0, 100)
|
|
25361
|
+
});
|
|
25362
|
+
}
|
|
25363
|
+
return out2;
|
|
25364
|
+
}
|
|
25365
|
+
function findGoPatternFindings(code, file) {
|
|
25366
|
+
const out2 = [];
|
|
25367
|
+
const lines = code.split(`
|
|
25368
|
+
`);
|
|
25369
|
+
const cipherVars = new Set;
|
|
25370
|
+
const ctorRe = /\b([a-zA-Z_]\w*)\s*(?:,\s*[a-zA-Z_]\w*)?\s*:?=\s*aes\.NewCipher\s*\(/;
|
|
25371
|
+
for (const line of lines) {
|
|
25372
|
+
const m = line.match(ctorRe);
|
|
25373
|
+
if (m)
|
|
25374
|
+
cipherVars.add(m[1]);
|
|
25375
|
+
}
|
|
25376
|
+
if (cipherVars.size === 0)
|
|
25377
|
+
return out2;
|
|
25378
|
+
for (const v of Array.from(cipherVars)) {
|
|
25379
|
+
const wrapRe = new RegExp(`\\bcipher\\.New(?:GCM|CBCEncrypter|CBCDecrypter|CTR|OFB|CFBEncrypter|CFBDecrypter)\\s*\\(\\s*${v}\\b`);
|
|
25380
|
+
for (const line of lines) {
|
|
25381
|
+
if (wrapRe.test(line)) {
|
|
25382
|
+
cipherVars.delete(v);
|
|
25383
|
+
break;
|
|
25384
|
+
}
|
|
25385
|
+
}
|
|
25386
|
+
}
|
|
25387
|
+
if (cipherVars.size === 0)
|
|
25388
|
+
return out2;
|
|
25389
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
25390
|
+
const raw = lines[i2];
|
|
25391
|
+
const trimmed = raw.trim();
|
|
25392
|
+
if (!trimmed || trimmed.startsWith("//"))
|
|
25393
|
+
continue;
|
|
25394
|
+
for (const v of cipherVars) {
|
|
25395
|
+
const opRe = new RegExp(`\\b${v}\\s*\\.\\s*(?:Encrypt|Decrypt)\\s*\\(`);
|
|
25396
|
+
if (!opRe.test(trimmed))
|
|
25397
|
+
continue;
|
|
25398
|
+
out2.push({
|
|
25399
|
+
id: `weak-crypto-${file}-${i2 + 1}`,
|
|
25400
|
+
pass: "language-sources",
|
|
25401
|
+
category: "security",
|
|
25402
|
+
rule_id: "weak-crypto",
|
|
25403
|
+
cwe: "CWE-327",
|
|
25404
|
+
severity: "high",
|
|
25405
|
+
level: "error",
|
|
25406
|
+
message: "Weak crypto (ECB mode): raw aes.Cipher.Encrypt/Decrypt on a " + "block leaks repeating-block patterns. Wrap with cipher.NewGCM, " + "cipher.NewCTR, or cipher.NewCBCEncrypter + HMAC.",
|
|
25407
|
+
file,
|
|
25408
|
+
line: i2 + 1,
|
|
25409
|
+
snippet: trimmed.substring(0, 100)
|
|
25410
|
+
});
|
|
25411
|
+
break;
|
|
25412
|
+
}
|
|
25413
|
+
}
|
|
25414
|
+
return out2;
|
|
25415
|
+
}
|
|
25416
|
+
function findJsPatternFindings(code, file) {
|
|
25417
|
+
const out2 = [];
|
|
25418
|
+
const lines = code.split(`
|
|
25419
|
+
`);
|
|
25420
|
+
const parseRe = /\blibxml(?:js)?\s*\.\s*parseXml(?:String)?\s*\(/;
|
|
25421
|
+
const noentTrueRe = /\bnoent\s*:\s*true\b/;
|
|
25422
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
25423
|
+
const raw = lines[i2];
|
|
25424
|
+
const trimmed = raw.trim();
|
|
25425
|
+
if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("*"))
|
|
25426
|
+
continue;
|
|
25427
|
+
if (!parseRe.test(trimmed))
|
|
25428
|
+
continue;
|
|
25429
|
+
if (!noentTrueRe.test(trimmed))
|
|
25430
|
+
continue;
|
|
25431
|
+
out2.push({
|
|
25432
|
+
id: `xml-entity-expansion-${file}-${i2 + 1}`,
|
|
25433
|
+
pass: "language-sources",
|
|
25434
|
+
category: "security",
|
|
25435
|
+
rule_id: "xml-entity-expansion",
|
|
25436
|
+
cwe: "CWE-611",
|
|
25437
|
+
severity: "high",
|
|
25438
|
+
level: "error",
|
|
25439
|
+
message: "XML external entity resolution enabled: libxmljs parseXml " + "called with `noent: true` resolves external entities (XXE / " + "billion-laughs). Omit the flag or set `noent: false`.",
|
|
25440
|
+
file,
|
|
25441
|
+
line: i2 + 1,
|
|
25442
|
+
snippet: trimmed.substring(0, 100)
|
|
25443
|
+
});
|
|
25444
|
+
}
|
|
25445
|
+
return out2;
|
|
25446
|
+
}
|
|
24997
25447
|
|
|
24998
25448
|
// ../circle-ir/dist/analysis/passes/sink-filter-pass.js
|
|
24999
25449
|
var JS_XSS_SANITIZERS = [
|
|
@@ -38121,7 +38571,7 @@ var colors = {
|
|
|
38121
38571
|
};
|
|
38122
38572
|
|
|
38123
38573
|
// src/version.ts
|
|
38124
|
-
var version = "3.
|
|
38574
|
+
var version = "3.129.0";
|
|
38125
38575
|
|
|
38126
38576
|
// src/formatters.ts
|
|
38127
38577
|
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": "3.
|
|
3
|
+
"version": "3.129.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",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@cognium/project-profile-detect": "^1.1.0",
|
|
69
|
-
"circle-ir": "^3.
|
|
69
|
+
"circle-ir": "^3.129.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/node": "^25.5.0",
|