cognium-dev 3.119.0 → 3.121.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 +178 -14
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -22082,6 +22082,126 @@ function truncate(s, maxLen) {
|
|
|
22082
22082
|
return s.length > maxLen ? s.slice(0, maxLen) + "..." : s;
|
|
22083
22083
|
}
|
|
22084
22084
|
|
|
22085
|
+
// ../circle-ir/dist/analysis/html/vue-template-xss-pass.js
|
|
22086
|
+
var DANGEROUS_BINDINGS = new Set([
|
|
22087
|
+
"v-html",
|
|
22088
|
+
"v-bind:innerhtml",
|
|
22089
|
+
":innerhtml",
|
|
22090
|
+
"v-bind:outerhtml",
|
|
22091
|
+
":outerhtml"
|
|
22092
|
+
]);
|
|
22093
|
+
var ID_RE = /\b([A-Za-z_$][A-Za-z0-9_$]*)\b/g;
|
|
22094
|
+
var RESERVED = new Set([
|
|
22095
|
+
"true",
|
|
22096
|
+
"false",
|
|
22097
|
+
"null",
|
|
22098
|
+
"undefined",
|
|
22099
|
+
"this",
|
|
22100
|
+
"new",
|
|
22101
|
+
"typeof",
|
|
22102
|
+
"void",
|
|
22103
|
+
"delete",
|
|
22104
|
+
"instanceof",
|
|
22105
|
+
"in",
|
|
22106
|
+
"of",
|
|
22107
|
+
"Math",
|
|
22108
|
+
"Number",
|
|
22109
|
+
"String",
|
|
22110
|
+
"Boolean",
|
|
22111
|
+
"Array",
|
|
22112
|
+
"Object",
|
|
22113
|
+
"JSON"
|
|
22114
|
+
]);
|
|
22115
|
+
function runVueTemplateXssChecks(rootNode, filePath, scriptResults) {
|
|
22116
|
+
const taintedNames = collectTaintedNames(scriptResults);
|
|
22117
|
+
if (taintedNames.size === 0)
|
|
22118
|
+
return [];
|
|
22119
|
+
const findings = [];
|
|
22120
|
+
const stack = [rootNode];
|
|
22121
|
+
while (stack.length > 0) {
|
|
22122
|
+
const node = stack.pop();
|
|
22123
|
+
if (node.type === "start_tag" || node.type === "self_closing_tag") {
|
|
22124
|
+
checkElementBindings(node, filePath, taintedNames, findings);
|
|
22125
|
+
}
|
|
22126
|
+
for (let i2 = node.childCount - 1;i2 >= 0; i2--) {
|
|
22127
|
+
const c = node.child(i2);
|
|
22128
|
+
if (c)
|
|
22129
|
+
stack.push(c);
|
|
22130
|
+
}
|
|
22131
|
+
}
|
|
22132
|
+
return findings;
|
|
22133
|
+
}
|
|
22134
|
+
function checkElementBindings(tag, filePath, tainted, out2) {
|
|
22135
|
+
for (let i2 = 0;i2 < tag.childCount; i2++) {
|
|
22136
|
+
const attr = tag.child(i2);
|
|
22137
|
+
if (!attr || attr.type !== "attribute")
|
|
22138
|
+
continue;
|
|
22139
|
+
const nameNode = findChildByType2(attr, "attribute_name");
|
|
22140
|
+
if (!nameNode)
|
|
22141
|
+
continue;
|
|
22142
|
+
const lcName = nameNode.text.toLowerCase();
|
|
22143
|
+
if (!DANGEROUS_BINDINGS.has(lcName))
|
|
22144
|
+
continue;
|
|
22145
|
+
const valueNode = findChildByType2(attr, "quoted_attribute_value") ?? findChildByType2(attr, "attribute_value");
|
|
22146
|
+
if (!valueNode)
|
|
22147
|
+
continue;
|
|
22148
|
+
const rhs = stripQuotes2(valueNode.text);
|
|
22149
|
+
if (!rhs.trim())
|
|
22150
|
+
continue;
|
|
22151
|
+
const matched = matchTaint(rhs, tainted);
|
|
22152
|
+
if (!matched)
|
|
22153
|
+
continue;
|
|
22154
|
+
const line = nameNode.startPosition.row + 1;
|
|
22155
|
+
out2.push({
|
|
22156
|
+
id: `vue-template-xss-${filePath}-${line}-${lcName}`,
|
|
22157
|
+
pass: "vue-template-xss",
|
|
22158
|
+
category: "security",
|
|
22159
|
+
rule_id: "vue-template-xss",
|
|
22160
|
+
cwe: "CWE-79",
|
|
22161
|
+
severity: "high",
|
|
22162
|
+
level: "error",
|
|
22163
|
+
message: `Vue template attribute "${nameNode.text}" binds tainted identifier "${matched}" — writes raw HTML (XSS risk).`,
|
|
22164
|
+
file: filePath,
|
|
22165
|
+
line,
|
|
22166
|
+
snippet: `${nameNode.text}="${rhs}"`
|
|
22167
|
+
});
|
|
22168
|
+
}
|
|
22169
|
+
}
|
|
22170
|
+
function matchTaint(rhs, tainted) {
|
|
22171
|
+
ID_RE.lastIndex = 0;
|
|
22172
|
+
let m;
|
|
22173
|
+
while ((m = ID_RE.exec(rhs)) !== null) {
|
|
22174
|
+
const id = m[1];
|
|
22175
|
+
if (RESERVED.has(id))
|
|
22176
|
+
continue;
|
|
22177
|
+
if (tainted.has(id))
|
|
22178
|
+
return id;
|
|
22179
|
+
}
|
|
22180
|
+
return;
|
|
22181
|
+
}
|
|
22182
|
+
function collectTaintedNames(blocks) {
|
|
22183
|
+
const names = new Set;
|
|
22184
|
+
for (const { ir } of blocks) {
|
|
22185
|
+
const sourceLines = new Set;
|
|
22186
|
+
for (const source of ir.taint.sources) {
|
|
22187
|
+
sourceLines.add(source.line);
|
|
22188
|
+
if (source.variable)
|
|
22189
|
+
names.add(source.variable);
|
|
22190
|
+
}
|
|
22191
|
+
for (const def of ir.dfg.defs) {
|
|
22192
|
+
if (sourceLines.has(def.line) && def.variable)
|
|
22193
|
+
names.add(def.variable);
|
|
22194
|
+
}
|
|
22195
|
+
for (const flow of ir.taint.flows ?? []) {
|
|
22196
|
+
for (const step of flow.path ?? []) {
|
|
22197
|
+
if (step.variable)
|
|
22198
|
+
names.add(step.variable);
|
|
22199
|
+
}
|
|
22200
|
+
}
|
|
22201
|
+
}
|
|
22202
|
+
return names;
|
|
22203
|
+
}
|
|
22204
|
+
|
|
22085
22205
|
// ../circle-ir/dist/analysis/html/html-merge.js
|
|
22086
22206
|
function mergeHtmlResults(htmlMeta, scriptResults, attributeFindings) {
|
|
22087
22207
|
const allTypes = [];
|
|
@@ -23309,10 +23429,43 @@ function findBashTaintSources(sourceCode, dfg) {
|
|
|
23309
23429
|
return sources;
|
|
23310
23430
|
}
|
|
23311
23431
|
var BASH_CREDENTIAL_PATTERN = /^(.*?)(password|passwd|secret|api_?key|token|auth_token|private_key|access_key)\s*=\s*["']?([^"'\s$][^"'\s]*)["']?\s*$/i;
|
|
23432
|
+
var BASH_CHECKSUM_VERIFY_PATTERN = /\b(?:sha(?:1|224|256|384|512)sum|md5sum|cksum|b2sum)\s+(?:-c\b|--check\b)/;
|
|
23433
|
+
function collectChecksumVerifiedTmpPaths(lines) {
|
|
23434
|
+
const verified = new Set;
|
|
23435
|
+
for (const line of lines) {
|
|
23436
|
+
if (!BASH_CHECKSUM_VERIFY_PATTERN.test(line))
|
|
23437
|
+
continue;
|
|
23438
|
+
const matches = line.match(/\/tmp\/[^\s"'$|`]+/g);
|
|
23439
|
+
if (!matches)
|
|
23440
|
+
continue;
|
|
23441
|
+
for (const p of matches)
|
|
23442
|
+
verified.add(p);
|
|
23443
|
+
}
|
|
23444
|
+
return verified;
|
|
23445
|
+
}
|
|
23446
|
+
var BASH_ARCHIVE_EXT_PATTERN = /\.(?:tgz|tar\.gz|tar\.bz2|tar\.xz|tar|tbz2|txz|zip|gz|bz2|xz|7z)$/i;
|
|
23447
|
+
function isArchiveOutputContext(line, tmpRel) {
|
|
23448
|
+
if (!BASH_ARCHIVE_EXT_PATTERN.test(tmpRel))
|
|
23449
|
+
return false;
|
|
23450
|
+
if (/\btar\b/.test(line) && /(?:^|\s)-?[A-Za-z]*c[A-Za-z]*\b/.test(line))
|
|
23451
|
+
return true;
|
|
23452
|
+
if (/\bzip\b/.test(line) && !/\bunzip\b/.test(line))
|
|
23453
|
+
return true;
|
|
23454
|
+
if (/\bgzip\b/.test(line) && /(?:-c\b|--stdout\b|>)/.test(line))
|
|
23455
|
+
return true;
|
|
23456
|
+
if (/\bbzip2\b/.test(line) && /(?:-c\b|--stdout\b|>)/.test(line))
|
|
23457
|
+
return true;
|
|
23458
|
+
if (/\bxz\b/.test(line) && /(?:-c\b|--stdout\b|>)/.test(line))
|
|
23459
|
+
return true;
|
|
23460
|
+
if (/\b7z\s+a\b/.test(line))
|
|
23461
|
+
return true;
|
|
23462
|
+
return false;
|
|
23463
|
+
}
|
|
23312
23464
|
function findBashPatternFindings(sourceCode, file) {
|
|
23313
23465
|
const findings = [];
|
|
23314
23466
|
const lines = sourceCode.split(`
|
|
23315
23467
|
`);
|
|
23468
|
+
const checksumVerifiedTmpPaths = collectChecksumVerifiedTmpPaths(lines);
|
|
23316
23469
|
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
23317
23470
|
const line = lines[i2];
|
|
23318
23471
|
const trimmed = line.trim();
|
|
@@ -23355,19 +23508,25 @@ function findBashPatternFindings(sourceCode, file) {
|
|
|
23355
23508
|
}
|
|
23356
23509
|
const tmpMatch = trimmed.match(/\/tmp\/([^\s"'$]+)/);
|
|
23357
23510
|
if (tmpMatch && !/mktemp/.test(trimmed)) {
|
|
23358
|
-
|
|
23359
|
-
|
|
23360
|
-
|
|
23361
|
-
|
|
23362
|
-
|
|
23363
|
-
|
|
23364
|
-
|
|
23365
|
-
|
|
23366
|
-
|
|
23367
|
-
|
|
23368
|
-
|
|
23369
|
-
|
|
23370
|
-
|
|
23511
|
+
const tmpRel = tmpMatch[1];
|
|
23512
|
+
const tmpPath = `/tmp/${tmpRel}`;
|
|
23513
|
+
const isChecksumVerified = checksumVerifiedTmpPaths.has(tmpPath);
|
|
23514
|
+
const isArchiveOutput = isArchiveOutputContext(trimmed, tmpRel);
|
|
23515
|
+
if (!isChecksumVerified && !isArchiveOutput) {
|
|
23516
|
+
findings.push({
|
|
23517
|
+
id: `predictable-temp-file-${file}-${lineNumber}`,
|
|
23518
|
+
pass: "language-sources",
|
|
23519
|
+
category: "security",
|
|
23520
|
+
rule_id: "predictable-temp-file",
|
|
23521
|
+
cwe: "CWE-377",
|
|
23522
|
+
severity: "medium",
|
|
23523
|
+
level: "warning",
|
|
23524
|
+
message: `Predictable temp file: /tmp/${tmpRel}. Use mktemp instead`,
|
|
23525
|
+
file,
|
|
23526
|
+
line: lineNumber,
|
|
23527
|
+
snippet: trimmed.substring(0, 80)
|
|
23528
|
+
});
|
|
23529
|
+
}
|
|
23371
23530
|
}
|
|
23372
23531
|
if (/\bchmod\b/.test(trimmed) && /\b(777|666)\b/.test(trimmed)) {
|
|
23373
23532
|
const mode = trimmed.match(/\b(777|666)\b/)[1];
|
|
@@ -36208,6 +36367,11 @@ async function analyzeMarkupFile(code, filePath, options, language) {
|
|
|
36208
36367
|
}
|
|
36209
36368
|
}
|
|
36210
36369
|
const attributeFindings = runHtmlAttributeSecurityChecks(tree.rootNode, filePath);
|
|
36370
|
+
if (language === "vue") {
|
|
36371
|
+
const vueXss = runVueTemplateXssChecks(tree.rootNode, filePath, scriptResults);
|
|
36372
|
+
if (vueXss.length > 0)
|
|
36373
|
+
attributeFindings.push(...vueXss);
|
|
36374
|
+
}
|
|
36211
36375
|
const result = mergeHtmlResults(meta, scriptResults, attributeFindings);
|
|
36212
36376
|
result.parse_status = htmlParseStatus;
|
|
36213
36377
|
logger.debug("HTML analysis complete", {
|
|
@@ -36904,7 +37068,7 @@ var colors = {
|
|
|
36904
37068
|
};
|
|
36905
37069
|
|
|
36906
37070
|
// src/version.ts
|
|
36907
|
-
var version = "3.
|
|
37071
|
+
var version = "3.121.0";
|
|
36908
37072
|
|
|
36909
37073
|
// src/formatters.ts
|
|
36910
37074
|
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.121.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.121.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/node": "^25.5.0",
|