cognium-dev 3.83.0 → 3.84.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 +271 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -12047,6 +12047,61 @@ function isSafeGoExecCommandCall(call, pattern, language) {
|
|
|
12047
12047
|
return false;
|
|
12048
12048
|
return true;
|
|
12049
12049
|
}
|
|
12050
|
+
function isSafeRustCommandCall(call, pattern, language) {
|
|
12051
|
+
if (language !== "rust")
|
|
12052
|
+
return false;
|
|
12053
|
+
if (pattern.type !== "command_injection")
|
|
12054
|
+
return false;
|
|
12055
|
+
if (pattern.class !== undefined && pattern.class !== "Command")
|
|
12056
|
+
return false;
|
|
12057
|
+
const SHELL_PROGRAMS = new Set([
|
|
12058
|
+
"sh",
|
|
12059
|
+
"bash",
|
|
12060
|
+
"zsh",
|
|
12061
|
+
"dash",
|
|
12062
|
+
"ash",
|
|
12063
|
+
"ksh",
|
|
12064
|
+
"cmd",
|
|
12065
|
+
"cmd.exe",
|
|
12066
|
+
"powershell",
|
|
12067
|
+
"pwsh",
|
|
12068
|
+
"powershell.exe",
|
|
12069
|
+
"pwsh.exe"
|
|
12070
|
+
]);
|
|
12071
|
+
const PROGRAM_RE = /\bCommand\s*::\s*new\s*\(\s*(?:r?"([^"]*)"|'([^']*)')/;
|
|
12072
|
+
const extractProgram = (text) => {
|
|
12073
|
+
const m = PROGRAM_RE.exec(text);
|
|
12074
|
+
if (!m)
|
|
12075
|
+
return null;
|
|
12076
|
+
const lit = m[1] ?? m[2] ?? "";
|
|
12077
|
+
return lit.split("/").pop() ?? lit;
|
|
12078
|
+
};
|
|
12079
|
+
if (pattern.method === "new") {
|
|
12080
|
+
const programArg = call.arguments.find((a) => a.position === 0);
|
|
12081
|
+
if (!programArg)
|
|
12082
|
+
return false;
|
|
12083
|
+
let program;
|
|
12084
|
+
if (programArg.literal !== null && programArg.literal !== undefined) {
|
|
12085
|
+
program = String(programArg.literal).split("/").pop() ?? String(programArg.literal);
|
|
12086
|
+
} else {
|
|
12087
|
+
const expr = (programArg.expression ?? "").trim();
|
|
12088
|
+
if (!(expr.startsWith('"') || expr.startsWith("'"))) {
|
|
12089
|
+
return false;
|
|
12090
|
+
}
|
|
12091
|
+
const stripped = expr.slice(1, -1);
|
|
12092
|
+
program = stripped.split("/").pop() ?? stripped;
|
|
12093
|
+
}
|
|
12094
|
+
return !SHELL_PROGRAMS.has(program);
|
|
12095
|
+
}
|
|
12096
|
+
if (pattern.method === "arg" || pattern.method === "args" || pattern.method === "spawn" || pattern.method === "output") {
|
|
12097
|
+
const receiverText = call.receiver ?? "";
|
|
12098
|
+
const program = extractProgram(receiverText);
|
|
12099
|
+
if (program === null)
|
|
12100
|
+
return false;
|
|
12101
|
+
return !SHELL_PROGRAMS.has(program);
|
|
12102
|
+
}
|
|
12103
|
+
return false;
|
|
12104
|
+
}
|
|
12050
12105
|
var CLASS_LITERAL_RE = /^(?:[A-Za-z_][\w]*\.)*[A-Z][\w]*(?:\[\])*\.class$/;
|
|
12051
12106
|
function argIsClassLiteral(call, position) {
|
|
12052
12107
|
const arg = call.arguments.find((a) => a.position === position);
|
|
@@ -12071,6 +12126,9 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
|
|
|
12071
12126
|
if (isSafeGoExecCommandCall(call, pattern, language)) {
|
|
12072
12127
|
continue;
|
|
12073
12128
|
}
|
|
12129
|
+
if (isSafeRustCommandCall(call, pattern, language)) {
|
|
12130
|
+
continue;
|
|
12131
|
+
}
|
|
12074
12132
|
if (pattern.safe_if_class_literal_at !== undefined && argIsClassLiteral(call, pattern.safe_if_class_literal_at)) {
|
|
12075
12133
|
continue;
|
|
12076
12134
|
}
|
|
@@ -21307,6 +21365,14 @@ class LanguageSourcesPass {
|
|
|
21307
21365
|
additionalSanitizers.push(...findGoMapAllowlistGuardSanitizers(code));
|
|
21308
21366
|
additionalSanitizers.push(...findGoHtmlTemplateImportSanitizers(code));
|
|
21309
21367
|
}
|
|
21368
|
+
if (language === "python") {
|
|
21369
|
+
additionalSanitizers.push(...findPythonNetlocAllowlistGuardSanitizers(code));
|
|
21370
|
+
additionalSanitizers.push(...findPythonRangeCheckGuardSanitizers(code));
|
|
21371
|
+
}
|
|
21372
|
+
if (language === "rust") {
|
|
21373
|
+
additionalSanitizers.push(...findRustSetAllowlistGuardSanitizers(code));
|
|
21374
|
+
additionalSanitizers.push(...findRustCanonicalizeGuardSanitizers(code));
|
|
21375
|
+
}
|
|
21310
21376
|
attachSourceLineCode(additionalSources, additionalSinks, code);
|
|
21311
21377
|
return { additionalSources, additionalSinks, additionalSanitizers, pyTaintedVars, pySanitizedVars, jsTaintedVars };
|
|
21312
21378
|
}
|
|
@@ -22421,6 +22487,210 @@ function findGoHtmlTemplateImportSanitizers(code) {
|
|
|
22421
22487
|
}
|
|
22422
22488
|
return sanitizers;
|
|
22423
22489
|
}
|
|
22490
|
+
function findPythonNetlocAllowlistGuardSanitizers(code) {
|
|
22491
|
+
const sanitizers = [];
|
|
22492
|
+
const lines = code.split(`
|
|
22493
|
+
`);
|
|
22494
|
+
const guardOpen = /^(\s*)if\s+.+?\s+not\s+in\s+([A-Za-z_][A-Za-z0-9_]*)\s*:\s*$/;
|
|
22495
|
+
const allowlistName = /^(?:[A-Z][A-Z0-9_]+|.*?(allowed|accepted|whitelist|permitted|valid|approved).*)$/i;
|
|
22496
|
+
const terminator = /\b(return|raise|abort\s*\(|sys\.exit\s*\()/;
|
|
22497
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
22498
|
+
const m = guardOpen.exec(lines[i2]);
|
|
22499
|
+
if (!m)
|
|
22500
|
+
continue;
|
|
22501
|
+
const guardIndent = m[1].length;
|
|
22502
|
+
const allowName = m[2];
|
|
22503
|
+
if (!allowlistName.test(allowName))
|
|
22504
|
+
continue;
|
|
22505
|
+
let bodyHasTerminator = false;
|
|
22506
|
+
let blockEnd = -1;
|
|
22507
|
+
const maxScan = Math.min(lines.length, i2 + 26);
|
|
22508
|
+
for (let j = i2 + 1;j < maxScan; j++) {
|
|
22509
|
+
const line = lines[j];
|
|
22510
|
+
if (line.trim() === "")
|
|
22511
|
+
continue;
|
|
22512
|
+
const indent = line.length - line.trimStart().length;
|
|
22513
|
+
if (indent <= guardIndent) {
|
|
22514
|
+
blockEnd = j - 1;
|
|
22515
|
+
break;
|
|
22516
|
+
}
|
|
22517
|
+
if (terminator.test(line))
|
|
22518
|
+
bodyHasTerminator = true;
|
|
22519
|
+
}
|
|
22520
|
+
if (blockEnd === -1)
|
|
22521
|
+
blockEnd = Math.min(lines.length - 1, i2 + 25);
|
|
22522
|
+
if (!bodyHasTerminator)
|
|
22523
|
+
continue;
|
|
22524
|
+
for (let l = blockEnd + 2;l <= lines.length; l++) {
|
|
22525
|
+
sanitizers.push({
|
|
22526
|
+
type: "python_netloc_allowlist_guard",
|
|
22527
|
+
method: "if",
|
|
22528
|
+
line: l,
|
|
22529
|
+
sanitizes: [
|
|
22530
|
+
"open_redirect",
|
|
22531
|
+
"ssrf",
|
|
22532
|
+
"path_traversal",
|
|
22533
|
+
"external_taint_escape"
|
|
22534
|
+
]
|
|
22535
|
+
});
|
|
22536
|
+
}
|
|
22537
|
+
}
|
|
22538
|
+
return sanitizers;
|
|
22539
|
+
}
|
|
22540
|
+
function findPythonRangeCheckGuardSanitizers(code) {
|
|
22541
|
+
const sanitizers = [];
|
|
22542
|
+
const lines = code.split(`
|
|
22543
|
+
`);
|
|
22544
|
+
const rangeGuard = /^(\s*)if\s+([A-Za-z_][A-Za-z0-9_]*)\s*[<>]=?\s*(?:\d+|-?\d+\.?\d*|[A-Z][A-Z0-9_]+)\s*(?:(?:or|and)\s+\2\s*[<>]=?\s*(?:\d+|-?\d+\.?\d*|[A-Z][A-Z0-9_]+)\s*)?:\s*$/;
|
|
22545
|
+
const terminator = /\b(return|raise|abort\s*\(|sys\.exit\s*\()/;
|
|
22546
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
22547
|
+
const m = rangeGuard.exec(lines[i2]);
|
|
22548
|
+
if (!m)
|
|
22549
|
+
continue;
|
|
22550
|
+
const guardIndent = m[1].length;
|
|
22551
|
+
let bodyHasTerminator = false;
|
|
22552
|
+
let blockEnd = -1;
|
|
22553
|
+
const maxScan = Math.min(lines.length, i2 + 26);
|
|
22554
|
+
for (let j = i2 + 1;j < maxScan; j++) {
|
|
22555
|
+
const line = lines[j];
|
|
22556
|
+
if (line.trim() === "")
|
|
22557
|
+
continue;
|
|
22558
|
+
const indent = line.length - line.trimStart().length;
|
|
22559
|
+
if (indent <= guardIndent) {
|
|
22560
|
+
blockEnd = j - 1;
|
|
22561
|
+
break;
|
|
22562
|
+
}
|
|
22563
|
+
if (terminator.test(line))
|
|
22564
|
+
bodyHasTerminator = true;
|
|
22565
|
+
}
|
|
22566
|
+
if (blockEnd === -1)
|
|
22567
|
+
blockEnd = Math.min(lines.length - 1, i2 + 25);
|
|
22568
|
+
if (!bodyHasTerminator)
|
|
22569
|
+
continue;
|
|
22570
|
+
for (let l = blockEnd + 2;l <= lines.length; l++) {
|
|
22571
|
+
sanitizers.push({
|
|
22572
|
+
type: "python_range_check_guard",
|
|
22573
|
+
method: "if",
|
|
22574
|
+
line: l,
|
|
22575
|
+
sanitizes: ["xss", "external_taint_escape"]
|
|
22576
|
+
});
|
|
22577
|
+
}
|
|
22578
|
+
}
|
|
22579
|
+
return sanitizers;
|
|
22580
|
+
}
|
|
22581
|
+
function findRustSetAllowlistGuardSanitizers(code) {
|
|
22582
|
+
const sanitizers = [];
|
|
22583
|
+
const lines = code.split(`
|
|
22584
|
+
`);
|
|
22585
|
+
const guardOpen = /^\s*if\s+!\s*([A-Za-z_][A-Za-z0-9_]*)\s*\.\s*(?:contains|contains_key)\s*\(/;
|
|
22586
|
+
const allowlistName = /^(?:[A-Z][A-Z0-9_]+|.*?(allowed|accepted|whitelist|permitted|valid|approved).*)$/i;
|
|
22587
|
+
const terminator = /\b(return|Err\s*\(|panic!\s*\(|HttpResponse::(?:Forbidden|BadRequest|Unauthorized))/;
|
|
22588
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
22589
|
+
const m = guardOpen.exec(lines[i2]);
|
|
22590
|
+
if (!m)
|
|
22591
|
+
continue;
|
|
22592
|
+
const setName = m[1];
|
|
22593
|
+
if (!allowlistName.test(setName))
|
|
22594
|
+
continue;
|
|
22595
|
+
let depth = 0;
|
|
22596
|
+
for (const ch of lines[i2]) {
|
|
22597
|
+
if (ch === "{")
|
|
22598
|
+
depth++;
|
|
22599
|
+
else if (ch === "}")
|
|
22600
|
+
depth--;
|
|
22601
|
+
}
|
|
22602
|
+
if (depth <= 0)
|
|
22603
|
+
continue;
|
|
22604
|
+
let closeLine = -1;
|
|
22605
|
+
let bodyHasTerminator = false;
|
|
22606
|
+
const maxScan = Math.min(lines.length, i2 + 26);
|
|
22607
|
+
for (let j = i2 + 1;j < maxScan; j++) {
|
|
22608
|
+
const line = lines[j];
|
|
22609
|
+
if (terminator.test(line))
|
|
22610
|
+
bodyHasTerminator = true;
|
|
22611
|
+
for (const ch of line) {
|
|
22612
|
+
if (ch === "{")
|
|
22613
|
+
depth++;
|
|
22614
|
+
else if (ch === "}")
|
|
22615
|
+
depth--;
|
|
22616
|
+
}
|
|
22617
|
+
if (depth === 0) {
|
|
22618
|
+
closeLine = j;
|
|
22619
|
+
break;
|
|
22620
|
+
}
|
|
22621
|
+
}
|
|
22622
|
+
if (closeLine === -1 || !bodyHasTerminator)
|
|
22623
|
+
continue;
|
|
22624
|
+
for (let l = closeLine + 2;l <= lines.length; l++) {
|
|
22625
|
+
sanitizers.push({
|
|
22626
|
+
type: "rust_set_allowlist_guard",
|
|
22627
|
+
method: "if",
|
|
22628
|
+
line: l,
|
|
22629
|
+
sanitizes: [
|
|
22630
|
+
"ssrf",
|
|
22631
|
+
"open_redirect",
|
|
22632
|
+
"command_injection",
|
|
22633
|
+
"external_taint_escape"
|
|
22634
|
+
]
|
|
22635
|
+
});
|
|
22636
|
+
}
|
|
22637
|
+
}
|
|
22638
|
+
return sanitizers;
|
|
22639
|
+
}
|
|
22640
|
+
function findRustCanonicalizeGuardSanitizers(code) {
|
|
22641
|
+
const sanitizers = [];
|
|
22642
|
+
const lines = code.split(`
|
|
22643
|
+
`);
|
|
22644
|
+
const guardOpen = /^\s*if\s+!\s*[A-Za-z_][\w?.()&]*\.starts_with\s*\(/;
|
|
22645
|
+
const terminator = /\b(return|Err\s*\(|panic!\s*\(|HttpResponse::(?:Forbidden|BadRequest|Unauthorized|NotFound))/;
|
|
22646
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
22647
|
+
if (!guardOpen.test(lines[i2]))
|
|
22648
|
+
continue;
|
|
22649
|
+
let depth = 0;
|
|
22650
|
+
for (const ch of lines[i2]) {
|
|
22651
|
+
if (ch === "{")
|
|
22652
|
+
depth++;
|
|
22653
|
+
else if (ch === "}")
|
|
22654
|
+
depth--;
|
|
22655
|
+
}
|
|
22656
|
+
if (depth <= 0)
|
|
22657
|
+
continue;
|
|
22658
|
+
let closeLine = -1;
|
|
22659
|
+
let bodyHasTerminator = false;
|
|
22660
|
+
const maxScan = Math.min(lines.length, i2 + 26);
|
|
22661
|
+
for (let j = i2 + 1;j < maxScan; j++) {
|
|
22662
|
+
const line = lines[j];
|
|
22663
|
+
if (terminator.test(line))
|
|
22664
|
+
bodyHasTerminator = true;
|
|
22665
|
+
for (const ch of line) {
|
|
22666
|
+
if (ch === "{")
|
|
22667
|
+
depth++;
|
|
22668
|
+
else if (ch === "}")
|
|
22669
|
+
depth--;
|
|
22670
|
+
}
|
|
22671
|
+
if (depth === 0) {
|
|
22672
|
+
closeLine = j;
|
|
22673
|
+
break;
|
|
22674
|
+
}
|
|
22675
|
+
}
|
|
22676
|
+
if (closeLine === -1 || !bodyHasTerminator)
|
|
22677
|
+
continue;
|
|
22678
|
+
for (let l = closeLine + 2;l <= lines.length; l++) {
|
|
22679
|
+
sanitizers.push({
|
|
22680
|
+
type: "rust_canonicalize_guard",
|
|
22681
|
+
method: "if",
|
|
22682
|
+
line: l,
|
|
22683
|
+
sanitizes: [
|
|
22684
|
+
"path_traversal",
|
|
22685
|
+
"xss",
|
|
22686
|
+
"ssrf",
|
|
22687
|
+
"external_taint_escape"
|
|
22688
|
+
]
|
|
22689
|
+
});
|
|
22690
|
+
}
|
|
22691
|
+
}
|
|
22692
|
+
return sanitizers;
|
|
22693
|
+
}
|
|
22424
22694
|
|
|
22425
22695
|
// ../circle-ir/dist/analysis/passes/sink-filter-pass.js
|
|
22426
22696
|
var JS_XSS_SANITIZERS = [
|
|
@@ -33586,7 +33856,7 @@ var colors = {
|
|
|
33586
33856
|
};
|
|
33587
33857
|
|
|
33588
33858
|
// src/version.ts
|
|
33589
|
-
var version = "3.
|
|
33859
|
+
var version = "3.84.0";
|
|
33590
33860
|
|
|
33591
33861
|
// src/formatters.ts
|
|
33592
33862
|
var SINK_SEVERITY = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.84.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.84.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/node": "^25.5.0",
|