cognium-dev 4.9.22 → 4.9.23
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 +288 -4
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -14400,6 +14400,35 @@ function classifyGoDestinationType(decl) {
|
|
|
14400
14400
|
return "unsafe";
|
|
14401
14401
|
return "safe";
|
|
14402
14402
|
}
|
|
14403
|
+
function isGoFprintToNonResponseWriter(call, pattern, language, sourceLines) {
|
|
14404
|
+
if (language !== "go")
|
|
14405
|
+
return false;
|
|
14406
|
+
if (pattern.type !== "xss" || pattern.class !== "fmt")
|
|
14407
|
+
return false;
|
|
14408
|
+
if (!/^Fprint(?:f|ln)?$/.test(call.method_name))
|
|
14409
|
+
return false;
|
|
14410
|
+
if (!sourceLines)
|
|
14411
|
+
return true;
|
|
14412
|
+
const writer = call.arguments.find((a) => a.position === 0);
|
|
14413
|
+
const name2 = (writer?.expression ?? "").trim();
|
|
14414
|
+
if (!/^[A-Za-z_]\w*$/.test(name2))
|
|
14415
|
+
return true;
|
|
14416
|
+
const rwRe = new RegExp(`\\b${name2}\\s+(?:net/)?http\\.ResponseWriter\\b`);
|
|
14417
|
+
for (let i2 = call.location.line - 1;i2 >= 0; i2--) {
|
|
14418
|
+
const line = sourceLines[i2] ?? "";
|
|
14419
|
+
const funcIdx = line.search(/\bfunc\b/);
|
|
14420
|
+
if (funcIdx < 0)
|
|
14421
|
+
continue;
|
|
14422
|
+
const header = sourceLines.slice(i2, i2 + 4).join(" ");
|
|
14423
|
+
const brace = header.indexOf("{");
|
|
14424
|
+
const params = header.slice(funcIdx, brace >= 0 ? brace : header.length);
|
|
14425
|
+
if (rwRe.test(params))
|
|
14426
|
+
return false;
|
|
14427
|
+
if (/^\s*func\b/.test(line))
|
|
14428
|
+
return true;
|
|
14429
|
+
}
|
|
14430
|
+
return true;
|
|
14431
|
+
}
|
|
14403
14432
|
function isSafeGoJsonUnmarshalCall(call, pattern, language, sourceLines) {
|
|
14404
14433
|
if (language !== "go")
|
|
14405
14434
|
return false;
|
|
@@ -14545,6 +14574,9 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines, types)
|
|
|
14545
14574
|
if (isSafeGoJsonUnmarshalCall(call, pattern, language, sourceLines)) {
|
|
14546
14575
|
continue;
|
|
14547
14576
|
}
|
|
14577
|
+
if (isGoFprintToNonResponseWriter(call, pattern, language, sourceLines)) {
|
|
14578
|
+
continue;
|
|
14579
|
+
}
|
|
14548
14580
|
if (isSafeJinjaRenderCall(call, pattern, language, sourceLines)) {
|
|
14549
14581
|
continue;
|
|
14550
14582
|
}
|
|
@@ -24126,7 +24158,23 @@ class GoPlugin extends BaseLanguagePlugin {
|
|
|
24126
24158
|
type: "xss",
|
|
24127
24159
|
cwe: "CWE-79",
|
|
24128
24160
|
severity: "high",
|
|
24129
|
-
argPositions: [1]
|
|
24161
|
+
argPositions: [1, 2, 3, 4, 5, 6]
|
|
24162
|
+
},
|
|
24163
|
+
{
|
|
24164
|
+
method: "Fprint",
|
|
24165
|
+
class: "fmt",
|
|
24166
|
+
type: "xss",
|
|
24167
|
+
cwe: "CWE-79",
|
|
24168
|
+
severity: "high",
|
|
24169
|
+
argPositions: [1, 2, 3, 4, 5, 6]
|
|
24170
|
+
},
|
|
24171
|
+
{
|
|
24172
|
+
method: "Fprintln",
|
|
24173
|
+
class: "fmt",
|
|
24174
|
+
type: "xss",
|
|
24175
|
+
cwe: "CWE-79",
|
|
24176
|
+
severity: "high",
|
|
24177
|
+
argPositions: [1, 2, 3, 4, 5, 6]
|
|
24130
24178
|
},
|
|
24131
24179
|
{
|
|
24132
24180
|
method: "Write",
|
|
@@ -25810,6 +25858,8 @@ class LanguageSourcesPass {
|
|
|
25810
25858
|
additionalSources.push(...findGoArgvSources(code, language));
|
|
25811
25859
|
additionalSources.push(...findGoArchiveEntrySources(code, language));
|
|
25812
25860
|
additionalSources.push(...findGoMultipartUploadSources(code, language));
|
|
25861
|
+
additionalSources.push(...findGoGrpcRequestSources(code, language));
|
|
25862
|
+
additionalSources.push(...findGoRequestBodySources(code, language));
|
|
25813
25863
|
const jsDOMSinks = findJavaScriptDOMSinks(code, language);
|
|
25814
25864
|
for (const s of jsDOMSinks) {
|
|
25815
25865
|
const alreadyExists = additionalSinks.some((x) => x.line === s.line && x.cwe === s.cwe);
|
|
@@ -26555,6 +26605,127 @@ function findGoMultipartUploadSources(sourceCode, language) {
|
|
|
26555
26605
|
}
|
|
26556
26606
|
return sources;
|
|
26557
26607
|
}
|
|
26608
|
+
function findGoGrpcRequestSources(sourceCode, language) {
|
|
26609
|
+
if (language !== "go")
|
|
26610
|
+
return [];
|
|
26611
|
+
if (!sourceCode.includes("context.Context"))
|
|
26612
|
+
return [];
|
|
26613
|
+
const sources = [];
|
|
26614
|
+
const lines = sourceCode.split(`
|
|
26615
|
+
`);
|
|
26616
|
+
const sigRe = /^func\s*\([^)]*\)\s*[A-Z]\w*\s*\(\s*\w+\s+context\.Context\s*,\s*([A-Za-z_]\w*)\s+\*(?:\w+\.)?\w*(?:Request|Req)\s*\)\s*\(\s*\*[\w.]+\s*,\s*error\s*\)\s*\{/;
|
|
26617
|
+
const controlRe = /^\s*(?:\}\s*else\s+)?(?:if|for|switch|case|return)\b/;
|
|
26618
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
26619
|
+
const sig = sigRe.exec(lines[i2]);
|
|
26620
|
+
if (!sig)
|
|
26621
|
+
continue;
|
|
26622
|
+
const param = sig[1];
|
|
26623
|
+
if (param === "_")
|
|
26624
|
+
continue;
|
|
26625
|
+
const readRe = new RegExp(`(?<![\\w.])${param}\\s*\\.\\s*(?:Get[A-Z]\\w*\\s*\\(\\s*\\)|[A-Z]\\w*\\b(?!\\s*\\())`);
|
|
26626
|
+
const directReadRe = new RegExp(`^(?:(?:\\[\\]\\w+|string)\\s*\\(\\s*)*${param}(?:\\s*\\.\\s*(?:Get[A-Z]\\w*\\s*\\(\\s*\\)|[A-Z]\\w*\\b(?!\\s*\\()))+(?:\\s*\\))*$`);
|
|
26627
|
+
const numericParseRe = new RegExp(`\\bstrconv\\s*\\.\\s*(?:Atoi|ParseInt|ParseUint|ParseFloat|ParseBool)\\s*\\(\\s*${param}\\s*\\.`);
|
|
26628
|
+
let end = i2 + 1;
|
|
26629
|
+
while (end < lines.length && !/^\}/.test(lines[end]))
|
|
26630
|
+
end++;
|
|
26631
|
+
for (let j = i2 + 1;j < end; j++) {
|
|
26632
|
+
const line = lines[j];
|
|
26633
|
+
const read = readRe.exec(line);
|
|
26634
|
+
if (!read)
|
|
26635
|
+
continue;
|
|
26636
|
+
if (numericParseRe.test(line))
|
|
26637
|
+
continue;
|
|
26638
|
+
let variable;
|
|
26639
|
+
const unmarshal = /\bUnmarshal\w*\s*\([^&]*&\s*([A-Za-z_]\w*)/.exec(line);
|
|
26640
|
+
const assign = /^\s*(?:var\s+)?([A-Za-z_][\w\s,]*?)\s*:?=(?!=)\s*(.+)$/.exec(line);
|
|
26641
|
+
if (unmarshal && line.indexOf(read[0]) < line.indexOf("&")) {
|
|
26642
|
+
variable = unmarshal[1];
|
|
26643
|
+
} else if (assign && directReadRe.test(assign[2].trim()) && !controlRe.test(line)) {
|
|
26644
|
+
variable = assign[1].split(",").map((v) => v.trim()).find((v) => v !== "_" && v !== "err" && v !== "ok" && /^[A-Za-z_]\w*$/.test(v));
|
|
26645
|
+
if (!variable)
|
|
26646
|
+
continue;
|
|
26647
|
+
} else if (controlRe.test(line)) {
|
|
26648
|
+
continue;
|
|
26649
|
+
} else {
|
|
26650
|
+
variable = param;
|
|
26651
|
+
}
|
|
26652
|
+
const lineNumber = j + 1;
|
|
26653
|
+
if (sources.some((sc) => sc.line === lineNumber && sc.variable === variable))
|
|
26654
|
+
continue;
|
|
26655
|
+
sources.push({
|
|
26656
|
+
type: "http_body",
|
|
26657
|
+
location: `${read[0].replace(/\s+/g, "")} — field of the gRPC request message \`${param}\``,
|
|
26658
|
+
severity: "high",
|
|
26659
|
+
line: lineNumber,
|
|
26660
|
+
confidence: 0.85,
|
|
26661
|
+
variable
|
|
26662
|
+
});
|
|
26663
|
+
}
|
|
26664
|
+
i2 = end;
|
|
26665
|
+
}
|
|
26666
|
+
return sources;
|
|
26667
|
+
}
|
|
26668
|
+
function findGoRequestBodySources(sourceCode, language) {
|
|
26669
|
+
if (language !== "go")
|
|
26670
|
+
return [];
|
|
26671
|
+
if (!sourceCode.includes(".Body"))
|
|
26672
|
+
return [];
|
|
26673
|
+
const lines = sourceCode.split(`
|
|
26674
|
+
`);
|
|
26675
|
+
const reqNames = new Set;
|
|
26676
|
+
const paramRe = /([A-Za-z_]\w*)\s+\*http\.Request\b/g;
|
|
26677
|
+
for (const line of lines) {
|
|
26678
|
+
let m;
|
|
26679
|
+
paramRe.lastIndex = 0;
|
|
26680
|
+
while ((m = paramRe.exec(line)) !== null)
|
|
26681
|
+
reqNames.add(m[1]);
|
|
26682
|
+
}
|
|
26683
|
+
if (reqNames.size === 0)
|
|
26684
|
+
return [];
|
|
26685
|
+
const bodyAlt = [...reqNames].map((n) => n.replace(/\$/g, "\\$")).join("|");
|
|
26686
|
+
const bodyRef = `(?<![\\w.])(?:${bodyAlt})\\s*\\.\\s*Body\\b`;
|
|
26687
|
+
const sources = [];
|
|
26688
|
+
const push = (variable, line, how) => {
|
|
26689
|
+
if (variable === "_" || variable === "")
|
|
26690
|
+
return;
|
|
26691
|
+
if (sources.some((s) => s.line === line && s.variable === variable))
|
|
26692
|
+
return;
|
|
26693
|
+
sources.push({
|
|
26694
|
+
type: "http_body",
|
|
26695
|
+
location: `${how} — HTTP request body`,
|
|
26696
|
+
severity: "high",
|
|
26697
|
+
line,
|
|
26698
|
+
confidence: 0.85,
|
|
26699
|
+
...variable ? { variable } : {}
|
|
26700
|
+
});
|
|
26701
|
+
};
|
|
26702
|
+
const bodyRe = new RegExp(bodyRef);
|
|
26703
|
+
const decodeRe = new RegExp(`(?:json|xml)\\s*\\.\\s*NewDecoder\\s*\\(\\s*(?:io\\.NopCloser\\s*\\(\\s*)?(?:${bodyAlt})\\s*\\.\\s*Body\\b[^)]*\\)\\s*\\)?\\s*\\.\\s*Decode\\s*\\(\\s*&\\s*([A-Za-z_]\\w*)`);
|
|
26704
|
+
const readAllRe = new RegExp(`\\b([A-Za-z_]\\w*)\\s*,\\s*\\w+\\s*:?=\\s*(?:io|ioutil)\\s*\\.\\s*ReadAll\\s*\\(\\s*(?:${bodyAlt})\\s*\\.\\s*Body\\b`);
|
|
26705
|
+
const copyRe = new RegExp(`\\bio\\s*\\.\\s*Copy\\s*\\(\\s*([A-Za-z_]\\w*|&\\s*[A-Za-z_]\\w*)\\s*,\\s*(?:${bodyAlt})\\s*\\.\\s*Body\\b`);
|
|
26706
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
26707
|
+
const line = lines[i2];
|
|
26708
|
+
if (!bodyRe.test(line))
|
|
26709
|
+
continue;
|
|
26710
|
+
const n = i2 + 1;
|
|
26711
|
+
const dec = decodeRe.exec(line);
|
|
26712
|
+
if (dec) {
|
|
26713
|
+
push(dec[1], n, `json/xml decode of ${dec[0].split(".")[0]}.Body`);
|
|
26714
|
+
continue;
|
|
26715
|
+
}
|
|
26716
|
+
const ra = readAllRe.exec(line);
|
|
26717
|
+
if (ra) {
|
|
26718
|
+
push(ra[1], n, "io.ReadAll(req.Body)");
|
|
26719
|
+
continue;
|
|
26720
|
+
}
|
|
26721
|
+
const cp = copyRe.exec(line);
|
|
26722
|
+
if (cp) {
|
|
26723
|
+
push(cp[1].replace(/^&\s*/, ""), n, "io.Copy(dst, req.Body)");
|
|
26724
|
+
continue;
|
|
26725
|
+
}
|
|
26726
|
+
}
|
|
26727
|
+
return sources;
|
|
26728
|
+
}
|
|
26558
26729
|
function findCSharpRequestSources(sourceCode, language) {
|
|
26559
26730
|
if (language !== "csharp")
|
|
26560
26731
|
return [];
|
|
@@ -37790,6 +37961,116 @@ function pickScopedSource(sources, sinkLine, methodName, types, taintedVar) {
|
|
|
37790
37961
|
}
|
|
37791
37962
|
|
|
37792
37963
|
// ../circle-ir/dist/analysis/interprocedural.js
|
|
37964
|
+
var GO_BUILTIN_CALLS = new Set([
|
|
37965
|
+
"len",
|
|
37966
|
+
"cap",
|
|
37967
|
+
"make",
|
|
37968
|
+
"new",
|
|
37969
|
+
"append",
|
|
37970
|
+
"copy",
|
|
37971
|
+
"delete",
|
|
37972
|
+
"close",
|
|
37973
|
+
"panic",
|
|
37974
|
+
"recover",
|
|
37975
|
+
"print",
|
|
37976
|
+
"println",
|
|
37977
|
+
"min",
|
|
37978
|
+
"max",
|
|
37979
|
+
"clear",
|
|
37980
|
+
"string",
|
|
37981
|
+
"int",
|
|
37982
|
+
"int8",
|
|
37983
|
+
"int16",
|
|
37984
|
+
"int32",
|
|
37985
|
+
"int64",
|
|
37986
|
+
"uint",
|
|
37987
|
+
"uint8",
|
|
37988
|
+
"uint16",
|
|
37989
|
+
"uint32",
|
|
37990
|
+
"uint64",
|
|
37991
|
+
"float32",
|
|
37992
|
+
"float64",
|
|
37993
|
+
"bool",
|
|
37994
|
+
"byte",
|
|
37995
|
+
"rune",
|
|
37996
|
+
"error"
|
|
37997
|
+
]);
|
|
37998
|
+
var GO_ERROR_AND_LOG_CALLS = new Set([
|
|
37999
|
+
"Errorf",
|
|
38000
|
+
"Sprintf",
|
|
38001
|
+
"Sprint",
|
|
38002
|
+
"Sprintln",
|
|
38003
|
+
"Print",
|
|
38004
|
+
"Printf",
|
|
38005
|
+
"Println",
|
|
38006
|
+
"Fatal",
|
|
38007
|
+
"Fatalf",
|
|
38008
|
+
"Fatalln",
|
|
38009
|
+
"Panic",
|
|
38010
|
+
"Panicf",
|
|
38011
|
+
"Panicln",
|
|
38012
|
+
"Debug",
|
|
38013
|
+
"Debugf",
|
|
38014
|
+
"Debugln",
|
|
38015
|
+
"Debugw",
|
|
38016
|
+
"Info",
|
|
38017
|
+
"Infof",
|
|
38018
|
+
"Infoln",
|
|
38019
|
+
"Infow",
|
|
38020
|
+
"InfoS",
|
|
38021
|
+
"Warn",
|
|
38022
|
+
"Warnf",
|
|
38023
|
+
"Warnln",
|
|
38024
|
+
"Warnw",
|
|
38025
|
+
"Warning",
|
|
38026
|
+
"Warningf",
|
|
38027
|
+
"Warningln",
|
|
38028
|
+
"Error",
|
|
38029
|
+
"Errorln",
|
|
38030
|
+
"Errorw",
|
|
38031
|
+
"ErrorS",
|
|
38032
|
+
"Trace",
|
|
38033
|
+
"Tracef",
|
|
38034
|
+
"V",
|
|
38035
|
+
"WithError",
|
|
38036
|
+
"WithField",
|
|
38037
|
+
"WithFields",
|
|
38038
|
+
"WithValues",
|
|
38039
|
+
"Msg",
|
|
38040
|
+
"Msgf"
|
|
38041
|
+
]);
|
|
38042
|
+
var GO_ERROR_PACKAGES = new Set(["errors", "status", "xerrors", "multierr", "multierror"]);
|
|
38043
|
+
var GO_PURE_PACKAGES = new Set([
|
|
38044
|
+
"strings",
|
|
38045
|
+
"strconv",
|
|
38046
|
+
"bytes",
|
|
38047
|
+
"unicode",
|
|
38048
|
+
"utf8",
|
|
38049
|
+
"path",
|
|
38050
|
+
"filepath",
|
|
38051
|
+
"math",
|
|
38052
|
+
"sort",
|
|
38053
|
+
"slices",
|
|
38054
|
+
"maps",
|
|
38055
|
+
"time",
|
|
38056
|
+
"regexp",
|
|
38057
|
+
"url",
|
|
38058
|
+
"hex",
|
|
38059
|
+
"base64"
|
|
38060
|
+
]);
|
|
38061
|
+
function isGoNonEscapeCall(call) {
|
|
38062
|
+
const name2 = call.method_name;
|
|
38063
|
+
const recv = (call.receiver ?? "").split(".").pop() ?? "";
|
|
38064
|
+
if (!call.receiver && GO_BUILTIN_CALLS.has(name2))
|
|
38065
|
+
return true;
|
|
38066
|
+
if (GO_ERROR_PACKAGES.has(recv))
|
|
38067
|
+
return true;
|
|
38068
|
+
if (GO_PURE_PACKAGES.has(recv))
|
|
38069
|
+
return true;
|
|
38070
|
+
if (GO_ERROR_AND_LOG_CALLS.has(name2))
|
|
38071
|
+
return true;
|
|
38072
|
+
return false;
|
|
38073
|
+
}
|
|
37793
38074
|
function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourcesOrSanitizers, sinksOrOptions, sanitizersArg, optionsArg = {}) {
|
|
37794
38075
|
let graph;
|
|
37795
38076
|
let sources;
|
|
@@ -38021,6 +38302,9 @@ function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourc
|
|
|
38021
38302
|
if (!targetMethod) {
|
|
38022
38303
|
if (taintedArgPositions.length > 0 && !collectionMethods.has(call.method_name) && !sanitizerMethods.has(call.method_name) && !safeUtilityMethods.has(call.method_name) && !ormQueryBuilderMethods.has(call.method_name)) {
|
|
38023
38304
|
const isBash = graph.ir.meta.language === "bash";
|
|
38305
|
+
if (graph.ir.meta.language === "go" && isGoNonEscapeCall(call)) {
|
|
38306
|
+
continue;
|
|
38307
|
+
}
|
|
38024
38308
|
const bashSafeBuiltins = new Set([
|
|
38025
38309
|
"echo",
|
|
38026
38310
|
"printf",
|
|
@@ -49846,7 +50130,7 @@ var colors = {
|
|
|
49846
50130
|
};
|
|
49847
50131
|
|
|
49848
50132
|
// src/version.ts
|
|
49849
|
-
var version = "4.9.
|
|
50133
|
+
var version = "4.9.23";
|
|
49850
50134
|
|
|
49851
50135
|
// src/formatters.ts
|
|
49852
50136
|
var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
|
|
@@ -50391,8 +50675,8 @@ function generateSarifResults(results, crossFileData) {
|
|
|
50391
50675
|
|
|
50392
50676
|
// src/build-info.ts
|
|
50393
50677
|
var buildInfo = {
|
|
50394
|
-
gitSha: "
|
|
50395
|
-
builtAt: "2026-09-
|
|
50678
|
+
gitSha: "e7e65f8",
|
|
50679
|
+
builtAt: "2026-09-22T22:15:34.355Z"
|
|
50396
50680
|
};
|
|
50397
50681
|
|
|
50398
50682
|
// src/utils/args.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.23",
|
|
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",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@cognium/project-profile-detect": "1.1.1",
|
|
70
|
-
"circle-ir": "4.9.
|
|
70
|
+
"circle-ir": "4.9.23"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@types/node": "^26.6.1",
|