cognium-dev 3.121.0 → 3.124.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 +715 -4
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -11692,7 +11692,8 @@ var PYTHON_TAINTED_PATTERNS = [
|
|
|
11692
11692
|
{ pattern: /\brequest\.META\b/, sourceType: "http_header" },
|
|
11693
11693
|
{ pattern: /\brequest\.FILES\b/, sourceType: "file_input" },
|
|
11694
11694
|
{ pattern: /\brequest\.query_params\b/, sourceType: "http_param" },
|
|
11695
|
-
{ pattern: /\brequest\.path_params\b/, sourceType: "http_param" }
|
|
11695
|
+
{ pattern: /\brequest\.path_params\b/, sourceType: "http_param" },
|
|
11696
|
+
{ pattern: /\binput\s*\(/, sourceType: "io_input" }
|
|
11696
11697
|
];
|
|
11697
11698
|
function analyzeTaint(calls, types, config = getDefaultConfig(), typeHierarchy, language, code) {
|
|
11698
11699
|
const sourceLines = code !== undefined ? code.split(`
|
|
@@ -22511,7 +22512,8 @@ var PYTHON_TAINTED_PATTERNS2 = [
|
|
|
22511
22512
|
{ pattern: /\bget_form_parameter\s*\(/, type: "http_body" },
|
|
22512
22513
|
{ pattern: /\bget_query_parameter\s*\(/, type: "http_param" },
|
|
22513
22514
|
{ pattern: /\bget_header_value\s*\(/, type: "http_header" },
|
|
22514
|
-
{ pattern: /\bget_cookie_value\s*\(/, type: "http_cookie" }
|
|
22515
|
+
{ pattern: /\bget_cookie_value\s*\(/, type: "http_cookie" },
|
|
22516
|
+
{ pattern: /\binput\s*\(/, type: "io_input" }
|
|
22515
22517
|
];
|
|
22516
22518
|
|
|
22517
22519
|
class LanguageSourcesPass {
|
|
@@ -22571,6 +22573,19 @@ class LanguageSourcesPass {
|
|
|
22571
22573
|
});
|
|
22572
22574
|
}
|
|
22573
22575
|
}
|
|
22576
|
+
for (const r of findPythonReflectionInvocationSinks(code, pyTaintedVars)) {
|
|
22577
|
+
const alreadyExists = additionalSinks.some((s) => s.line === r.sinkLine && s.type === "code_injection" && s.method === r.method);
|
|
22578
|
+
if (!alreadyExists) {
|
|
22579
|
+
additionalSinks.push({
|
|
22580
|
+
type: "code_injection",
|
|
22581
|
+
cwe: "CWE-94",
|
|
22582
|
+
line: r.sinkLine,
|
|
22583
|
+
location: `reflection invocation (getattr result called) with tainted attribute name at line ${r.sinkLine}`,
|
|
22584
|
+
method: r.method,
|
|
22585
|
+
confidence: 0.85
|
|
22586
|
+
});
|
|
22587
|
+
}
|
|
22588
|
+
}
|
|
22574
22589
|
}
|
|
22575
22590
|
const jsTaintedVars = buildJavaScriptTaintedVars(code, language);
|
|
22576
22591
|
if (language === "bash") {
|
|
@@ -22589,10 +22604,33 @@ class LanguageSourcesPass {
|
|
|
22589
22604
|
if (language === "python") {
|
|
22590
22605
|
additionalSanitizers.push(...findPythonNetlocAllowlistGuardSanitizers(code));
|
|
22591
22606
|
additionalSanitizers.push(...findPythonRangeCheckGuardSanitizers(code));
|
|
22607
|
+
const pyMisconfigFindings = findPythonPatternFindings(code, graph.ir.meta.file);
|
|
22608
|
+
for (const finding of pyMisconfigFindings) {
|
|
22609
|
+
ctx.addFinding(finding);
|
|
22610
|
+
}
|
|
22592
22611
|
}
|
|
22593
22612
|
if (language === "rust") {
|
|
22594
22613
|
additionalSanitizers.push(...findRustSetAllowlistGuardSanitizers(code));
|
|
22595
22614
|
additionalSanitizers.push(...findRustCanonicalizeGuardSanitizers(code));
|
|
22615
|
+
const rustMisconfigFindings = findRustPatternFindings(code, graph.ir.meta.file);
|
|
22616
|
+
for (const finding of rustMisconfigFindings) {
|
|
22617
|
+
ctx.addFinding(finding);
|
|
22618
|
+
}
|
|
22619
|
+
}
|
|
22620
|
+
if (language === "javascript" || language === "typescript" || language === "htmljs") {
|
|
22621
|
+
additionalSanitizers.push(...findJsSafeJsonParseSanitizers(code));
|
|
22622
|
+
additionalSanitizers.push(...findJsCryptoHashSanitizers(code));
|
|
22623
|
+
additionalSanitizers.push(...findJsCsvFormulaPrefixSanitizers(code));
|
|
22624
|
+
additionalSanitizers.push(...findJsWrapperFunctionSanitizers(code));
|
|
22625
|
+
}
|
|
22626
|
+
if (language === "java") {
|
|
22627
|
+
additionalSanitizers.push(...findJavaSafeJsonParseSanitizers(code));
|
|
22628
|
+
}
|
|
22629
|
+
if (language === "python" || language === "javascript" || language === "typescript" || language === "go") {
|
|
22630
|
+
const exfilFindings = findExternalSecretExfiltrationFindings(code, graph.ir.meta.file, language);
|
|
22631
|
+
for (const finding of exfilFindings) {
|
|
22632
|
+
ctx.addFinding(finding);
|
|
22633
|
+
}
|
|
22596
22634
|
}
|
|
22597
22635
|
attachSourceLineCode(additionalSources, additionalSinks, code);
|
|
22598
22636
|
return { additionalSources, additionalSinks, additionalSanitizers, pyTaintedVars, pySanitizedVars, jsTaintedVars };
|
|
@@ -23219,6 +23257,51 @@ function findPythonReturnXSSSinks(sourceCode, taintedVars) {
|
|
|
23219
23257
|
}
|
|
23220
23258
|
return sinks;
|
|
23221
23259
|
}
|
|
23260
|
+
function findPythonReflectionInvocationSinks(sourceCode, taintedVars) {
|
|
23261
|
+
if (taintedVars.size === 0)
|
|
23262
|
+
return [];
|
|
23263
|
+
const sinks = [];
|
|
23264
|
+
const lines = sourceCode.split(`
|
|
23265
|
+
`);
|
|
23266
|
+
const directRe = /\bgetattr\s*\(\s*[^,()]+\s*,\s*([A-Za-z_][\w]*)\s*\)\s*\(/;
|
|
23267
|
+
const bindRe = /^\s*([A-Za-z_][\w]*)\s*=\s*getattr\s*\(\s*[^,()]+\s*,\s*([A-Za-z_][\w]*)\s*\)\s*$/;
|
|
23268
|
+
const aliases = [];
|
|
23269
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
23270
|
+
const line = lines[i2];
|
|
23271
|
+
if (line.trimStart().startsWith("#"))
|
|
23272
|
+
continue;
|
|
23273
|
+
const dm = line.match(directRe);
|
|
23274
|
+
if (dm && taintedVars.has(dm[1])) {
|
|
23275
|
+
sinks.push({ sinkLine: i2 + 1, method: "getattr" });
|
|
23276
|
+
continue;
|
|
23277
|
+
}
|
|
23278
|
+
const bm = line.match(bindRe);
|
|
23279
|
+
if (bm && taintedVars.has(bm[2])) {
|
|
23280
|
+
aliases.push({ name: bm[1], bindLine: i2 + 1 });
|
|
23281
|
+
}
|
|
23282
|
+
}
|
|
23283
|
+
if (aliases.length === 0)
|
|
23284
|
+
return sinks;
|
|
23285
|
+
const firedBindLines = new Set;
|
|
23286
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
23287
|
+
const line = lines[i2];
|
|
23288
|
+
if (line.trimStart().startsWith("#"))
|
|
23289
|
+
continue;
|
|
23290
|
+
const lineNum = i2 + 1;
|
|
23291
|
+
for (const a of aliases) {
|
|
23292
|
+
if (lineNum <= a.bindLine)
|
|
23293
|
+
continue;
|
|
23294
|
+
if (firedBindLines.has(a.bindLine))
|
|
23295
|
+
continue;
|
|
23296
|
+
const invokeRe = new RegExp(`(?<![\\w.])${a.name}\\s*\\(`);
|
|
23297
|
+
if (invokeRe.test(line)) {
|
|
23298
|
+
sinks.push({ sinkLine: a.bindLine, method: "getattr" });
|
|
23299
|
+
firedBindLines.add(a.bindLine);
|
|
23300
|
+
}
|
|
23301
|
+
}
|
|
23302
|
+
}
|
|
23303
|
+
return sinks;
|
|
23304
|
+
}
|
|
23222
23305
|
function findJavaScriptDOMSinks(sourceCode, language) {
|
|
23223
23306
|
if (!["javascript", "typescript"].includes(language))
|
|
23224
23307
|
return [];
|
|
@@ -23466,6 +23549,7 @@ function findBashPatternFindings(sourceCode, file) {
|
|
|
23466
23549
|
const lines = sourceCode.split(`
|
|
23467
23550
|
`);
|
|
23468
23551
|
const checksumVerifiedTmpPaths = collectChecksumVerifiedTmpPaths(lines);
|
|
23552
|
+
const scriptHasVerifier = hasIntegrityVerifierAnywhere(lines);
|
|
23469
23553
|
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
23470
23554
|
const line = lines[i2];
|
|
23471
23555
|
const trimmed = line.trim();
|
|
@@ -23559,9 +23643,79 @@ function findBashPatternFindings(sourceCode, file) {
|
|
|
23559
23643
|
snippet: trimmed.substring(0, 80)
|
|
23560
23644
|
});
|
|
23561
23645
|
}
|
|
23646
|
+
if (!scriptHasVerifier) {
|
|
23647
|
+
const installer = matchUnverifiedPackageInstall(trimmed);
|
|
23648
|
+
if (installer) {
|
|
23649
|
+
findings.push({
|
|
23650
|
+
id: `unverified-package-install-${file}-${lineNumber}`,
|
|
23651
|
+
pass: "language-sources",
|
|
23652
|
+
category: "security",
|
|
23653
|
+
rule_id: "unverified-package-install",
|
|
23654
|
+
cwe: "CWE-494",
|
|
23655
|
+
severity: "high",
|
|
23656
|
+
level: "error",
|
|
23657
|
+
message: `Unverified package install via ${installer}: package contents are not integrity-checked (no gpg/sha256sum verify in script)`,
|
|
23658
|
+
file,
|
|
23659
|
+
line: lineNumber,
|
|
23660
|
+
snippet: trimmed.substring(0, 80)
|
|
23661
|
+
});
|
|
23662
|
+
}
|
|
23663
|
+
}
|
|
23664
|
+
const weakHashAlg = matchBashWeakHashCommand(trimmed);
|
|
23665
|
+
if (weakHashAlg) {
|
|
23666
|
+
findings.push({
|
|
23667
|
+
id: `weak-hash-${file}-${lineNumber}`,
|
|
23668
|
+
pass: "language-sources",
|
|
23669
|
+
category: "security",
|
|
23670
|
+
rule_id: "weak-hash",
|
|
23671
|
+
cwe: "CWE-328",
|
|
23672
|
+
severity: "medium",
|
|
23673
|
+
level: "warning",
|
|
23674
|
+
message: `Weak hash algorithm: ${weakHashAlg} is cryptographically broken. Use sha256sum or sha512sum`,
|
|
23675
|
+
file,
|
|
23676
|
+
line: lineNumber,
|
|
23677
|
+
snippet: trimmed.substring(0, 80)
|
|
23678
|
+
});
|
|
23679
|
+
}
|
|
23562
23680
|
}
|
|
23563
23681
|
return findings;
|
|
23564
23682
|
}
|
|
23683
|
+
function matchBashWeakHashCommand(line) {
|
|
23684
|
+
const re = /(?:^|[|;]|&&|\|\|)\s*(md5sum|sha1sum|md5|sha1)\b(?!\s*=)/;
|
|
23685
|
+
const m = line.match(re);
|
|
23686
|
+
if (!m)
|
|
23687
|
+
return null;
|
|
23688
|
+
return m[1];
|
|
23689
|
+
}
|
|
23690
|
+
function matchUnverifiedPackageInstall(line) {
|
|
23691
|
+
if (/\bdpkg\b/.test(line) && /(?:^|\s)(?:-[a-zA-Z]*[iIU][a-zA-Z]*|--install)\b/.test(line)) {
|
|
23692
|
+
return "dpkg";
|
|
23693
|
+
}
|
|
23694
|
+
if (/\brpm\b/.test(line) && /(?:^|\s)(?:-[a-zA-Z]*[iU][a-zA-Z]*|--install|--upgrade)\b/.test(line) && !/--(?:verify|checksig|erase|query)\b/.test(line)) {
|
|
23695
|
+
return "rpm";
|
|
23696
|
+
}
|
|
23697
|
+
const aptMatch = line.match(/\b(apt-get|apt|aptitude)\s+install\b/);
|
|
23698
|
+
if (aptMatch && /\.deb\b/.test(line)) {
|
|
23699
|
+
return aptMatch[1];
|
|
23700
|
+
}
|
|
23701
|
+
const yumMatch = line.match(/\b(yum|dnf|zypper)\s+install\b/);
|
|
23702
|
+
if (yumMatch && /\.rpm\b/.test(line)) {
|
|
23703
|
+
return yumMatch[1];
|
|
23704
|
+
}
|
|
23705
|
+
return null;
|
|
23706
|
+
}
|
|
23707
|
+
function hasIntegrityVerifierAnywhere(lines) {
|
|
23708
|
+
const sigRe = /\b(?:gpg(?:v|2)?|gpg)\s+(?:[^|]*\s)?--verify\b/;
|
|
23709
|
+
const rpmSigRe = /\brpm\s+(?:[^|]*\s)?--checksig\b/;
|
|
23710
|
+
const dpkgSigRe = /\bdpkg\s+(?:[^|]*\s)?--verify\b/;
|
|
23711
|
+
const sumRe = /\b(?:sha(?:1|224|256|384|512)sum|md5sum|cksum|b2sum)\s+(?:[^|]*\s)?(?:-c|--check)\b/;
|
|
23712
|
+
for (const line of lines) {
|
|
23713
|
+
if (sigRe.test(line) || rpmSigRe.test(line) || dpkgSigRe.test(line) || sumRe.test(line)) {
|
|
23714
|
+
return true;
|
|
23715
|
+
}
|
|
23716
|
+
}
|
|
23717
|
+
return false;
|
|
23718
|
+
}
|
|
23565
23719
|
function findBashRegexAllowlistSanitizers(code) {
|
|
23566
23720
|
const sanitizers = [];
|
|
23567
23721
|
const lines = code.split(`
|
|
@@ -23967,6 +24121,537 @@ function findRustCanonicalizeGuardSanitizers(code) {
|
|
|
23967
24121
|
}
|
|
23968
24122
|
return sanitizers;
|
|
23969
24123
|
}
|
|
24124
|
+
function findJavaSafeJsonParseSanitizers(code) {
|
|
24125
|
+
const sanitizers = [];
|
|
24126
|
+
const lines = code.split(`
|
|
24127
|
+
`);
|
|
24128
|
+
const safeParse = /\.(?:readValue|fromJson)\s*\(/;
|
|
24129
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24130
|
+
if (!safeParse.test(lines[i2]))
|
|
24131
|
+
continue;
|
|
24132
|
+
sanitizers.push({
|
|
24133
|
+
type: "java_safe_json_parse",
|
|
24134
|
+
method: "readValue",
|
|
24135
|
+
line: i2 + 1,
|
|
24136
|
+
sanitizes: ["external_taint_escape"]
|
|
24137
|
+
});
|
|
24138
|
+
}
|
|
24139
|
+
return sanitizers;
|
|
24140
|
+
}
|
|
24141
|
+
function findJsSafeJsonParseSanitizers(code) {
|
|
24142
|
+
const sanitizers = [];
|
|
24143
|
+
const lines = code.split(`
|
|
24144
|
+
`);
|
|
24145
|
+
const safeParse = /\bJSON\.parse\s*\(/;
|
|
24146
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24147
|
+
if (!safeParse.test(lines[i2]))
|
|
24148
|
+
continue;
|
|
24149
|
+
sanitizers.push({
|
|
24150
|
+
type: "js_safe_json_parse",
|
|
24151
|
+
method: "JSON.parse",
|
|
24152
|
+
line: i2 + 1,
|
|
24153
|
+
sanitizes: ["external_taint_escape"]
|
|
24154
|
+
});
|
|
24155
|
+
}
|
|
24156
|
+
return sanitizers;
|
|
24157
|
+
}
|
|
24158
|
+
function findJsCryptoHashSanitizers(code) {
|
|
24159
|
+
const sanitizers = [];
|
|
24160
|
+
const lines = code.split(`
|
|
24161
|
+
`);
|
|
24162
|
+
const hashCall = /\b(?:bcrypt|argon2)\s*\.\s*hash(?:Sync)?\s*\(|\bcrypto\s*\.\s*(?:scrypt(?:Sync)?|createHash)\s*\(|\.digest\s*\(/;
|
|
24163
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24164
|
+
if (!hashCall.test(lines[i2]))
|
|
24165
|
+
continue;
|
|
24166
|
+
sanitizers.push({
|
|
24167
|
+
type: "js_crypto_hash",
|
|
24168
|
+
method: "hash",
|
|
24169
|
+
line: i2 + 1,
|
|
24170
|
+
sanitizes: ["external_taint_escape"]
|
|
24171
|
+
});
|
|
24172
|
+
}
|
|
24173
|
+
return sanitizers;
|
|
24174
|
+
}
|
|
24175
|
+
function findJsCsvFormulaPrefixSanitizers(code) {
|
|
24176
|
+
const sanitizers = [];
|
|
24177
|
+
const lines = code.split(`
|
|
24178
|
+
`);
|
|
24179
|
+
const tickPrefix = /`'\$\{/;
|
|
24180
|
+
const concatPrefix = /["']\\?'["']\s*\+\s*[A-Za-z_]/;
|
|
24181
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24182
|
+
if (tickPrefix.test(lines[i2]) || concatPrefix.test(lines[i2])) {
|
|
24183
|
+
sanitizers.push({
|
|
24184
|
+
type: "js_csv_formula_prefix",
|
|
24185
|
+
method: "'-prefix",
|
|
24186
|
+
line: i2 + 1,
|
|
24187
|
+
sanitizes: ["external_taint_escape"]
|
|
24188
|
+
});
|
|
24189
|
+
}
|
|
24190
|
+
}
|
|
24191
|
+
return sanitizers;
|
|
24192
|
+
}
|
|
24193
|
+
function findJsWrapperFunctionSanitizers(code) {
|
|
24194
|
+
const sanitizers = [];
|
|
24195
|
+
const lines = code.split(`
|
|
24196
|
+
`);
|
|
24197
|
+
const wrappers = new Map;
|
|
24198
|
+
const fnDeclRe = /\bfunction\s+([A-Za-z_]\w*)\s*\(/;
|
|
24199
|
+
const arrowDeclRe = /\b(?:const|let|var)\s+([A-Za-z_]\w*)\s*=\s*(?:\([^)]*\)|[A-Za-z_]\w*)\s*=>/;
|
|
24200
|
+
const xssCharClass = /\.replace\s*\(\s*\/[^/]*[&<>"'][^/]*\//;
|
|
24201
|
+
const crlfCharClass = /\.replace\s*\(\s*\/[^/]*(?:\\r|\\n|\\t)[^/]*\//;
|
|
24202
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24203
|
+
const m = fnDeclRe.exec(lines[i2]) ?? arrowDeclRe.exec(lines[i2]);
|
|
24204
|
+
if (!m)
|
|
24205
|
+
continue;
|
|
24206
|
+
const name2 = m[1];
|
|
24207
|
+
const body2 = lines.slice(i2, Math.min(lines.length, i2 + 8)).join(`
|
|
24208
|
+
`);
|
|
24209
|
+
const kinds = new Set;
|
|
24210
|
+
if (xssCharClass.test(body2)) {
|
|
24211
|
+
kinds.add("xss");
|
|
24212
|
+
kinds.add("external_taint_escape");
|
|
24213
|
+
}
|
|
24214
|
+
if (crlfCharClass.test(body2)) {
|
|
24215
|
+
kinds.add("log_injection");
|
|
24216
|
+
kinds.add("external_taint_escape");
|
|
24217
|
+
}
|
|
24218
|
+
if (kinds.size > 0)
|
|
24219
|
+
wrappers.set(name2, kinds);
|
|
24220
|
+
}
|
|
24221
|
+
if (wrappers.size === 0)
|
|
24222
|
+
return sanitizers;
|
|
24223
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24224
|
+
for (const [name2, kinds] of wrappers) {
|
|
24225
|
+
const declSelf = new RegExp(`\\b(?:function|const|let|var)\\s+${name2}\\b`);
|
|
24226
|
+
if (declSelf.test(lines[i2]))
|
|
24227
|
+
continue;
|
|
24228
|
+
const callRe = new RegExp(`\\b${name2}\\s*\\(`);
|
|
24229
|
+
if (!callRe.test(lines[i2]))
|
|
24230
|
+
continue;
|
|
24231
|
+
sanitizers.push({
|
|
24232
|
+
type: "js_wrapper_function",
|
|
24233
|
+
method: name2,
|
|
24234
|
+
line: i2 + 1,
|
|
24235
|
+
sanitizes: [...kinds]
|
|
24236
|
+
});
|
|
24237
|
+
}
|
|
24238
|
+
}
|
|
24239
|
+
return sanitizers;
|
|
24240
|
+
}
|
|
24241
|
+
function collectEnvSecretVars(lines, language) {
|
|
24242
|
+
const out2 = new Map;
|
|
24243
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24244
|
+
const line = lines[i2];
|
|
24245
|
+
if (language === "python") {
|
|
24246
|
+
const m = line.match(/^\s*(\w+)\s*=\s*os\.(?:environ\s*[\[.]|getenv\b)/);
|
|
24247
|
+
if (m)
|
|
24248
|
+
out2.set(m[1], i2 + 1);
|
|
24249
|
+
} else if (language === "javascript" || language === "typescript") {
|
|
24250
|
+
const m = line.match(/(?:^|\s|;)(?:const|let|var)\s+(\w+)\s*=\s*process\.env\b/);
|
|
24251
|
+
if (m)
|
|
24252
|
+
out2.set(m[1], i2 + 1);
|
|
24253
|
+
} else if (language === "go") {
|
|
24254
|
+
const m = line.match(/^\s*(\w+)\s*:?=\s*os\.Getenv\s*\(/);
|
|
24255
|
+
if (m)
|
|
24256
|
+
out2.set(m[1], i2 + 1);
|
|
24257
|
+
}
|
|
24258
|
+
}
|
|
24259
|
+
return out2;
|
|
24260
|
+
}
|
|
24261
|
+
function isExternalHostUrl(url) {
|
|
24262
|
+
const lower = url.toLowerCase();
|
|
24263
|
+
if (!/^https?:\/\//.test(lower))
|
|
24264
|
+
return false;
|
|
24265
|
+
const host = lower.replace(/^https?:\/\//, "").split(/[/?#:]/)[0];
|
|
24266
|
+
if (!host)
|
|
24267
|
+
return false;
|
|
24268
|
+
if (host === "localhost" || host === "127.0.0.1" || host === "0.0.0.0" || host === "::1")
|
|
24269
|
+
return false;
|
|
24270
|
+
if (/^10\./.test(host))
|
|
24271
|
+
return false;
|
|
24272
|
+
if (/^192\.168\./.test(host))
|
|
24273
|
+
return false;
|
|
24274
|
+
if (/^172\.(1[6-9]|2\d|3[01])\./.test(host))
|
|
24275
|
+
return false;
|
|
24276
|
+
if (host.includes(".internal.") || host.endsWith(".internal") || host.startsWith("internal."))
|
|
24277
|
+
return false;
|
|
24278
|
+
if (host.endsWith(".local") || host.endsWith(".lan") || host.endsWith(".corp"))
|
|
24279
|
+
return false;
|
|
24280
|
+
if (!host.includes("."))
|
|
24281
|
+
return false;
|
|
24282
|
+
return true;
|
|
24283
|
+
}
|
|
24284
|
+
function findBalancedCallEnd(code, start2) {
|
|
24285
|
+
let depth = 1;
|
|
24286
|
+
let i2 = start2;
|
|
24287
|
+
let inStr = null;
|
|
24288
|
+
while (i2 < code.length) {
|
|
24289
|
+
const ch = code[i2];
|
|
24290
|
+
if (inStr) {
|
|
24291
|
+
if (ch === "\\") {
|
|
24292
|
+
i2 += 2;
|
|
24293
|
+
continue;
|
|
24294
|
+
}
|
|
24295
|
+
if (ch === inStr)
|
|
24296
|
+
inStr = null;
|
|
24297
|
+
} else {
|
|
24298
|
+
if (ch === '"' || ch === "'" || ch === "`")
|
|
24299
|
+
inStr = ch;
|
|
24300
|
+
else if (ch === "(")
|
|
24301
|
+
depth++;
|
|
24302
|
+
else if (ch === ")") {
|
|
24303
|
+
depth--;
|
|
24304
|
+
if (depth === 0)
|
|
24305
|
+
return i2;
|
|
24306
|
+
}
|
|
24307
|
+
}
|
|
24308
|
+
i2++;
|
|
24309
|
+
}
|
|
24310
|
+
return -1;
|
|
24311
|
+
}
|
|
24312
|
+
function findKwargValueEnd(s, start2) {
|
|
24313
|
+
let depth = 0;
|
|
24314
|
+
let inStr = null;
|
|
24315
|
+
for (let i2 = start2;i2 < s.length; i2++) {
|
|
24316
|
+
const ch = s[i2];
|
|
24317
|
+
if (inStr) {
|
|
24318
|
+
if (ch === "\\") {
|
|
24319
|
+
i2++;
|
|
24320
|
+
continue;
|
|
24321
|
+
}
|
|
24322
|
+
if (ch === inStr)
|
|
24323
|
+
inStr = null;
|
|
24324
|
+
continue;
|
|
24325
|
+
}
|
|
24326
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
24327
|
+
inStr = ch;
|
|
24328
|
+
continue;
|
|
24329
|
+
}
|
|
24330
|
+
if (ch === "(" || ch === "[" || ch === "{")
|
|
24331
|
+
depth++;
|
|
24332
|
+
else if (ch === ")" || ch === "]" || ch === "}") {
|
|
24333
|
+
if (depth === 0)
|
|
24334
|
+
return i2;
|
|
24335
|
+
depth--;
|
|
24336
|
+
} else if (ch === "," && depth === 0) {
|
|
24337
|
+
return i2;
|
|
24338
|
+
}
|
|
24339
|
+
}
|
|
24340
|
+
return s.length;
|
|
24341
|
+
}
|
|
24342
|
+
function lineOfCharIndex(code, charIdx) {
|
|
24343
|
+
let line = 1;
|
|
24344
|
+
for (let i2 = 0;i2 < charIdx && i2 < code.length; i2++) {
|
|
24345
|
+
if (code[i2] === `
|
|
24346
|
+
`)
|
|
24347
|
+
line++;
|
|
24348
|
+
}
|
|
24349
|
+
return line;
|
|
24350
|
+
}
|
|
24351
|
+
function makeExfilFinding(file, line, snippet, fired, receiver) {
|
|
24352
|
+
return {
|
|
24353
|
+
id: `external-secret-exfiltration-${file}-${line}`,
|
|
24354
|
+
pass: "language-sources",
|
|
24355
|
+
category: "security",
|
|
24356
|
+
rule_id: "external-secret-exfiltration",
|
|
24357
|
+
cwe: "CWE-200",
|
|
24358
|
+
severity: "high",
|
|
24359
|
+
level: "error",
|
|
24360
|
+
message: `Environment secret(s) ${fired.join(", ")} transmitted in request body to external host via ${receiver}`,
|
|
24361
|
+
file,
|
|
24362
|
+
line,
|
|
24363
|
+
snippet: snippet.substring(0, 120)
|
|
24364
|
+
};
|
|
24365
|
+
}
|
|
24366
|
+
function findExternalSecretExfiltrationFindings(code, file, language) {
|
|
24367
|
+
const out2 = [];
|
|
24368
|
+
const lines = code.split(`
|
|
24369
|
+
`);
|
|
24370
|
+
const secretVars = collectEnvSecretVars(lines, language);
|
|
24371
|
+
if (secretVars.size === 0)
|
|
24372
|
+
return out2;
|
|
24373
|
+
if (language === "python") {
|
|
24374
|
+
out2.push(...findPythonExfilCalls(code, file, secretVars));
|
|
24375
|
+
} else if (language === "javascript" || language === "typescript") {
|
|
24376
|
+
out2.push(...findJavaScriptExfilCalls(code, file, secretVars));
|
|
24377
|
+
} else if (language === "go") {
|
|
24378
|
+
out2.push(...findGoExfilCalls(code, file, secretVars));
|
|
24379
|
+
}
|
|
24380
|
+
return out2;
|
|
24381
|
+
}
|
|
24382
|
+
function findPythonExfilCalls(code, file, secretVars) {
|
|
24383
|
+
const out2 = [];
|
|
24384
|
+
const callRe = /\b(requests|httpx)\.(post|put|patch|delete|request)\s*\(/g;
|
|
24385
|
+
let m;
|
|
24386
|
+
while (m = callRe.exec(code)) {
|
|
24387
|
+
const argStart = m.index + m[0].length;
|
|
24388
|
+
const argEnd = findBalancedCallEnd(code, argStart);
|
|
24389
|
+
if (argEnd < 0)
|
|
24390
|
+
continue;
|
|
24391
|
+
const args2 = code.slice(argStart, argEnd);
|
|
24392
|
+
const urlMatch = args2.match(/^\s*["']([^"']+)["']/);
|
|
24393
|
+
if (!urlMatch)
|
|
24394
|
+
continue;
|
|
24395
|
+
if (!isExternalHostUrl(urlMatch[1]))
|
|
24396
|
+
continue;
|
|
24397
|
+
const headersIdx = args2.search(/\bheaders\s*=/);
|
|
24398
|
+
let headersStr = "";
|
|
24399
|
+
let bodyStr = args2;
|
|
24400
|
+
if (headersIdx >= 0) {
|
|
24401
|
+
const eqIdx = args2.indexOf("=", headersIdx);
|
|
24402
|
+
const valueStart = eqIdx + 1;
|
|
24403
|
+
const headersEnd = findKwargValueEnd(args2, valueStart);
|
|
24404
|
+
headersStr = args2.slice(valueStart, headersEnd);
|
|
24405
|
+
bodyStr = args2.slice(0, headersIdx) + " " + args2.slice(headersEnd);
|
|
24406
|
+
}
|
|
24407
|
+
const fired = [];
|
|
24408
|
+
for (const v of secretVars.keys()) {
|
|
24409
|
+
const re = new RegExp(`\\b${v}\\b`);
|
|
24410
|
+
if (re.test(bodyStr) && !re.test(headersStr))
|
|
24411
|
+
fired.push(v);
|
|
24412
|
+
}
|
|
24413
|
+
if (fired.length > 0) {
|
|
24414
|
+
const line = lineOfCharIndex(code, m.index);
|
|
24415
|
+
out2.push(makeExfilFinding(file, line, code.slice(m.index, Math.min(argEnd + 1, m.index + 120)), fired, `${m[1]}.${m[2]}`));
|
|
24416
|
+
}
|
|
24417
|
+
}
|
|
24418
|
+
return out2;
|
|
24419
|
+
}
|
|
24420
|
+
function findJavaScriptExfilCalls(code, file, secretVars) {
|
|
24421
|
+
const out2 = [];
|
|
24422
|
+
const allLines = code.split(`
|
|
24423
|
+
`);
|
|
24424
|
+
const carriers = new Set;
|
|
24425
|
+
const carrierRe = /(?:^|[\s;{])(?:const|let|var)\s+(\w+)\s*=\s*([^;\n]+)/g;
|
|
24426
|
+
let cm;
|
|
24427
|
+
while (cm = carrierRe.exec(code)) {
|
|
24428
|
+
const name2 = cm[1];
|
|
24429
|
+
const rhs = cm[2];
|
|
24430
|
+
for (const v of secretVars.keys()) {
|
|
24431
|
+
if (new RegExp(`\\b${v}\\b`).test(rhs)) {
|
|
24432
|
+
carriers.add(name2);
|
|
24433
|
+
break;
|
|
24434
|
+
}
|
|
24435
|
+
}
|
|
24436
|
+
}
|
|
24437
|
+
const taintedRefs = new Set([...secretVars.keys(), ...carriers]);
|
|
24438
|
+
const networkRe = /\b(https?\.(?:request|get)|fetch|axios\.(?:post|put|patch|request|delete))\s*\(/g;
|
|
24439
|
+
let m;
|
|
24440
|
+
while (m = networkRe.exec(code)) {
|
|
24441
|
+
const argStart = m.index + m[0].length;
|
|
24442
|
+
const argEnd = findBalancedCallEnd(code, argStart);
|
|
24443
|
+
if (argEnd < 0)
|
|
24444
|
+
continue;
|
|
24445
|
+
const args2 = code.slice(argStart, argEnd);
|
|
24446
|
+
const urlMatch = args2.match(/^\s*(?:["']([^"']+)["']|`([^`$]+)`)/);
|
|
24447
|
+
if (!urlMatch)
|
|
24448
|
+
continue;
|
|
24449
|
+
const url = urlMatch[1] || urlMatch[2];
|
|
24450
|
+
if (!isExternalHostUrl(url))
|
|
24451
|
+
continue;
|
|
24452
|
+
const headersIdx = args2.search(/\bheaders\s*:/);
|
|
24453
|
+
let headersStr = "";
|
|
24454
|
+
let restStr = args2;
|
|
24455
|
+
if (headersIdx >= 0) {
|
|
24456
|
+
const valueStart = args2.indexOf(":", headersIdx) + 1;
|
|
24457
|
+
const headersEnd = findKwargValueEnd(args2, valueStart);
|
|
24458
|
+
headersStr = args2.slice(valueStart, headersEnd);
|
|
24459
|
+
restStr = args2.slice(0, headersIdx) + " " + args2.slice(headersEnd);
|
|
24460
|
+
}
|
|
24461
|
+
const fired = new Set;
|
|
24462
|
+
for (const v of taintedRefs) {
|
|
24463
|
+
const re = new RegExp(`\\b${v}\\b`);
|
|
24464
|
+
if (re.test(restStr) && !re.test(headersStr))
|
|
24465
|
+
fired.add(v);
|
|
24466
|
+
}
|
|
24467
|
+
const callLine = lineOfCharIndex(code, m.index);
|
|
24468
|
+
const windowEnd = Math.min(allLines.length, callLine + 20);
|
|
24469
|
+
const writeWindow = allLines.slice(callLine, windowEnd).join(`
|
|
24470
|
+
`);
|
|
24471
|
+
const writeRe = /\b\w+\.(?:write|end)\s*\(\s*(\w+)/g;
|
|
24472
|
+
let wm;
|
|
24473
|
+
while (wm = writeRe.exec(writeWindow)) {
|
|
24474
|
+
if (taintedRefs.has(wm[1]))
|
|
24475
|
+
fired.add(wm[1]);
|
|
24476
|
+
}
|
|
24477
|
+
if (fired.size > 0) {
|
|
24478
|
+
out2.push(makeExfilFinding(file, callLine, code.slice(m.index, Math.min(argEnd + 1, m.index + 120)), [...fired], m[1]));
|
|
24479
|
+
}
|
|
24480
|
+
}
|
|
24481
|
+
return out2;
|
|
24482
|
+
}
|
|
24483
|
+
function findGoExfilCalls(code, file, secretVars) {
|
|
24484
|
+
const out2 = [];
|
|
24485
|
+
const patterns = [
|
|
24486
|
+
{ re: /\bhttp\.PostForm\s*\(/g, urlArgIndex: 0, receiver: "http.PostForm" },
|
|
24487
|
+
{ re: /\bhttp\.Post\s*\(/g, urlArgIndex: 0, receiver: "http.Post" },
|
|
24488
|
+
{ re: /\bhttp\.NewRequest\s*\(/g, urlArgIndex: 1, receiver: "http.NewRequest" }
|
|
24489
|
+
];
|
|
24490
|
+
for (const { re, urlArgIndex, receiver } of patterns) {
|
|
24491
|
+
let m;
|
|
24492
|
+
while (m = re.exec(code)) {
|
|
24493
|
+
const argStart = m.index + m[0].length;
|
|
24494
|
+
const argEnd = findBalancedCallEnd(code, argStart);
|
|
24495
|
+
if (argEnd < 0)
|
|
24496
|
+
continue;
|
|
24497
|
+
const args2 = code.slice(argStart, argEnd);
|
|
24498
|
+
let urlSearchSlice = args2;
|
|
24499
|
+
if (urlArgIndex === 1) {
|
|
24500
|
+
const firstComma = findKwargValueEnd(args2, 0);
|
|
24501
|
+
if (firstComma >= args2.length)
|
|
24502
|
+
continue;
|
|
24503
|
+
urlSearchSlice = args2.slice(firstComma + 1);
|
|
24504
|
+
}
|
|
24505
|
+
const urlMatch = urlSearchSlice.match(/^\s*["`]([^"`]+)["`]/);
|
|
24506
|
+
if (!urlMatch)
|
|
24507
|
+
continue;
|
|
24508
|
+
if (!isExternalHostUrl(urlMatch[1]))
|
|
24509
|
+
continue;
|
|
24510
|
+
const fired = [];
|
|
24511
|
+
for (const v of secretVars.keys()) {
|
|
24512
|
+
if (new RegExp(`\\b${v}\\b`).test(args2))
|
|
24513
|
+
fired.push(v);
|
|
24514
|
+
}
|
|
24515
|
+
if (fired.length > 0) {
|
|
24516
|
+
const line = lineOfCharIndex(code, m.index);
|
|
24517
|
+
out2.push(makeExfilFinding(file, line, code.slice(m.index, Math.min(argEnd + 1, m.index + 120)), fired, receiver));
|
|
24518
|
+
}
|
|
24519
|
+
}
|
|
24520
|
+
}
|
|
24521
|
+
return out2;
|
|
24522
|
+
}
|
|
24523
|
+
function findPythonPatternFindings(code, file) {
|
|
24524
|
+
const out2 = [];
|
|
24525
|
+
const lines = code.split(`
|
|
24526
|
+
`);
|
|
24527
|
+
const subscriptHeaderRe = /\.headers\s*\[\s*['"]([^'"]+)['"]\s*\]\s*=\s*(.+)$/;
|
|
24528
|
+
const xfoHits = [];
|
|
24529
|
+
const cspHits = [];
|
|
24530
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24531
|
+
const raw = lines[i2];
|
|
24532
|
+
const trimmed = raw.trim();
|
|
24533
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
24534
|
+
continue;
|
|
24535
|
+
const lineNumber = i2 + 1;
|
|
24536
|
+
const sm = trimmed.match(subscriptHeaderRe);
|
|
24537
|
+
if (sm) {
|
|
24538
|
+
const headerName = sm[1];
|
|
24539
|
+
const rhs = sm[2].trim();
|
|
24540
|
+
const headerLower = headerName.toLowerCase();
|
|
24541
|
+
if (headerLower === "access-control-allow-origin") {
|
|
24542
|
+
const valMatch = rhs.match(/^['"]\*['"]/);
|
|
24543
|
+
if (valMatch) {
|
|
24544
|
+
out2.push({
|
|
24545
|
+
id: `cors-wildcard-origin-${file}-${lineNumber}`,
|
|
24546
|
+
pass: "language-sources",
|
|
24547
|
+
category: "security",
|
|
24548
|
+
rule_id: "cors-wildcard-origin",
|
|
24549
|
+
cwe: "CWE-942",
|
|
24550
|
+
severity: "medium",
|
|
24551
|
+
level: "warning",
|
|
24552
|
+
message: "CORS Access-Control-Allow-Origin set to wildcard '*': any origin may read responses",
|
|
24553
|
+
file,
|
|
24554
|
+
line: lineNumber,
|
|
24555
|
+
snippet: trimmed.substring(0, 100)
|
|
24556
|
+
});
|
|
24557
|
+
}
|
|
24558
|
+
}
|
|
24559
|
+
if (headerLower === "x-frame-options") {
|
|
24560
|
+
xfoHits.push({ line: lineNumber, value: rhs });
|
|
24561
|
+
} else if (headerLower === "content-security-policy") {
|
|
24562
|
+
cspHits.push({ line: lineNumber, value: rhs });
|
|
24563
|
+
}
|
|
24564
|
+
}
|
|
24565
|
+
if (/\bverify_mode\s*=\s*ssl\.CERT_NONE\b/.test(trimmed)) {
|
|
24566
|
+
out2.push({
|
|
24567
|
+
id: `tls-verify-disabled-${file}-${lineNumber}`,
|
|
24568
|
+
pass: "language-sources",
|
|
24569
|
+
category: "security",
|
|
24570
|
+
rule_id: "tls-verify-disabled",
|
|
24571
|
+
cwe: "CWE-295",
|
|
24572
|
+
severity: "high",
|
|
24573
|
+
level: "error",
|
|
24574
|
+
message: "TLS certificate verification disabled: ssl context verify_mode set to CERT_NONE",
|
|
24575
|
+
file,
|
|
24576
|
+
line: lineNumber,
|
|
24577
|
+
snippet: trimmed.substring(0, 100)
|
|
24578
|
+
});
|
|
24579
|
+
} else if (/\bcheck_hostname\s*=\s*False\b/.test(trimmed)) {
|
|
24580
|
+
out2.push({
|
|
24581
|
+
id: `tls-verify-disabled-${file}-${lineNumber}`,
|
|
24582
|
+
pass: "language-sources",
|
|
24583
|
+
category: "security",
|
|
24584
|
+
rule_id: "tls-verify-disabled",
|
|
24585
|
+
cwe: "CWE-295",
|
|
24586
|
+
severity: "high",
|
|
24587
|
+
level: "error",
|
|
24588
|
+
message: "TLS hostname verification disabled: ssl context check_hostname set to False",
|
|
24589
|
+
file,
|
|
24590
|
+
line: lineNumber,
|
|
24591
|
+
snippet: trimmed.substring(0, 100)
|
|
24592
|
+
});
|
|
24593
|
+
}
|
|
24594
|
+
}
|
|
24595
|
+
const restrictiveXfo = xfoHits.find((h) => /['"](?:DENY|SAMEORIGIN)['"]/i.test(h.value));
|
|
24596
|
+
const permissiveCsp = cspHits.find((h) => {
|
|
24597
|
+
const pm = h.value.match(/['"]([^'"]+)['"]/);
|
|
24598
|
+
if (!pm)
|
|
24599
|
+
return false;
|
|
24600
|
+
const policy = pm[1];
|
|
24601
|
+
const faMatch = policy.match(/frame-ancestors\s+([^;]+)/i);
|
|
24602
|
+
if (!faMatch)
|
|
24603
|
+
return false;
|
|
24604
|
+
const directive = faMatch[1].trim();
|
|
24605
|
+
return /(^|\s)\*(\s|$)/.test(directive) || /\bhttps?:\/\//i.test(directive);
|
|
24606
|
+
});
|
|
24607
|
+
if (restrictiveXfo && permissiveCsp) {
|
|
24608
|
+
out2.push({
|
|
24609
|
+
id: `xfo-csp-mismatch-${file}-${restrictiveXfo.line}`,
|
|
24610
|
+
pass: "language-sources",
|
|
24611
|
+
category: "security",
|
|
24612
|
+
rule_id: "xfo-csp-mismatch",
|
|
24613
|
+
cwe: "CWE-1021",
|
|
24614
|
+
severity: "medium",
|
|
24615
|
+
level: "warning",
|
|
24616
|
+
message: "X-Frame-Options/CSP frame-ancestors mismatch: XFO restricts framing but CSP frame-ancestors is permissive (CSP overrides on modern browsers)",
|
|
24617
|
+
file,
|
|
24618
|
+
line: restrictiveXfo.line,
|
|
24619
|
+
snippet: lines[restrictiveXfo.line - 1].trim().substring(0, 100)
|
|
24620
|
+
});
|
|
24621
|
+
}
|
|
24622
|
+
return out2;
|
|
24623
|
+
}
|
|
24624
|
+
function findRustPatternFindings(code, file) {
|
|
24625
|
+
const out2 = [];
|
|
24626
|
+
const lines = code.split(`
|
|
24627
|
+
`);
|
|
24628
|
+
const re = /\.\s*(danger_accept_invalid_certs|danger_accept_invalid_hostnames)\s*\(\s*true\s*\)/;
|
|
24629
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
24630
|
+
const raw = lines[i2];
|
|
24631
|
+
const trimmed = raw.trim();
|
|
24632
|
+
if (!trimmed || trimmed.startsWith("//"))
|
|
24633
|
+
continue;
|
|
24634
|
+
const m = trimmed.match(re);
|
|
24635
|
+
if (!m)
|
|
24636
|
+
continue;
|
|
24637
|
+
const method = m[1];
|
|
24638
|
+
const what = method === "danger_accept_invalid_certs" ? "certificate" : "hostname";
|
|
24639
|
+
out2.push({
|
|
24640
|
+
id: `tls-verify-disabled-${file}-${i2 + 1}`,
|
|
24641
|
+
pass: "language-sources",
|
|
24642
|
+
category: "security",
|
|
24643
|
+
rule_id: "tls-verify-disabled",
|
|
24644
|
+
cwe: "CWE-295",
|
|
24645
|
+
severity: "high",
|
|
24646
|
+
level: "error",
|
|
24647
|
+
message: `TLS ${what} verification disabled: reqwest builder ${method}(true)`,
|
|
24648
|
+
file,
|
|
24649
|
+
line: i2 + 1,
|
|
24650
|
+
snippet: trimmed.substring(0, 100)
|
|
24651
|
+
});
|
|
24652
|
+
}
|
|
24653
|
+
return out2;
|
|
24654
|
+
}
|
|
23970
24655
|
|
|
23971
24656
|
// ../circle-ir/dist/analysis/passes/sink-filter-pass.js
|
|
23972
24657
|
var JS_XSS_SANITIZERS = [
|
|
@@ -26453,7 +27138,33 @@ function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourc
|
|
|
26453
27138
|
if (isBash && bashSafeBuiltins.has(call.method_name)) {
|
|
26454
27139
|
continue;
|
|
26455
27140
|
}
|
|
26456
|
-
|
|
27141
|
+
if (isBash && taintedArgPositions.length > 0) {
|
|
27142
|
+
const terminatorPos = call.arguments.filter((a) => a.expression === "--").map((a) => a.position).reduce((min, p) => min === null || p < min ? p : min, null);
|
|
27143
|
+
const earliestTainted = Math.min(...taintedArgPositions);
|
|
27144
|
+
if (terminatorPos !== null && terminatorPos < earliestTainted) {
|
|
27145
|
+
const allTaintedQuoted = taintedArgPositions.every((p) => {
|
|
27146
|
+
const a = call.arguments[p];
|
|
27147
|
+
if (!a)
|
|
27148
|
+
return false;
|
|
27149
|
+
const expr = a.expression.trim();
|
|
27150
|
+
return expr.startsWith('"') && expr.endsWith('"');
|
|
27151
|
+
});
|
|
27152
|
+
if (allTaintedQuoted) {
|
|
27153
|
+
continue;
|
|
27154
|
+
}
|
|
27155
|
+
}
|
|
27156
|
+
}
|
|
27157
|
+
const bashSqlCliTools = new Set(["sqlite3", "mysql", "psql", "mariadb"]);
|
|
27158
|
+
const isBashSqlCli = isBash && bashSqlCliTools.has(call.method_name);
|
|
27159
|
+
const sink = isBashSqlCli ? {
|
|
27160
|
+
type: "sql_injection",
|
|
27161
|
+
cwe: "CWE-89",
|
|
27162
|
+
location: `Tainted data (${taintedArgVars.join(", ")}) interpolated into SQL query passed to ${call.method_name}`,
|
|
27163
|
+
line: call.location.line,
|
|
27164
|
+
confidence: 0.7,
|
|
27165
|
+
method: call.method_name,
|
|
27166
|
+
argPositions: taintedArgPositions
|
|
27167
|
+
} : isBash ? {
|
|
26457
27168
|
type: "command_injection",
|
|
26458
27169
|
cwe: "CWE-78",
|
|
26459
27170
|
location: `Tainted data (${taintedArgVars.join(", ")}) passed unquoted to shell utility ${call.method_name}`,
|
|
@@ -37068,7 +37779,7 @@ var colors = {
|
|
|
37068
37779
|
};
|
|
37069
37780
|
|
|
37070
37781
|
// src/version.ts
|
|
37071
|
-
var version = "3.
|
|
37782
|
+
var version = "3.124.0";
|
|
37072
37783
|
|
|
37073
37784
|
// src/formatters.ts
|
|
37074
37785
|
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.124.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.124.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/node": "^25.5.0",
|