cognium-dev 3.65.0 → 3.67.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 +313 -6
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -11038,9 +11038,11 @@ var DEFAULT_SINKS = [
|
|
|
11038
11038
|
{ method: "rmdir", class: "fs", type: "path_traversal", cwe: "CWE-22", severity: "critical", arg_positions: [0] },
|
|
11039
11039
|
{ method: "createReadStream", class: "fs", type: "path_traversal", cwe: "CWE-22", severity: "critical", arg_positions: [0] },
|
|
11040
11040
|
{ method: "createWriteStream", class: "fs", type: "path_traversal", cwe: "CWE-22", severity: "critical", arg_positions: [0] },
|
|
11041
|
-
{ method: "query", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
11042
|
-
{ method: "query", class: "Pool", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
11043
|
-
{ method: "query", class: "Client", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
11041
|
+
{ method: "query", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"], allow_unresolved_receiver: true },
|
|
11042
|
+
{ method: "query", class: "Pool", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"], allow_unresolved_receiver: true },
|
|
11043
|
+
{ method: "query", class: "Client", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"], allow_unresolved_receiver: true },
|
|
11044
|
+
{ method: "execute", class: "Pool", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"], allow_unresolved_receiver: true },
|
|
11045
|
+
{ method: "execute", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"], allow_unresolved_receiver: true },
|
|
11044
11046
|
{ method: "raw", type: "sql_injection", cwe: "CWE-89", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
11045
11047
|
{ method: "setAttribute", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [1] },
|
|
11046
11048
|
{ method: "send", class: "Response", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0] },
|
|
@@ -11053,6 +11055,9 @@ var DEFAULT_SINKS = [
|
|
|
11053
11055
|
{ method: "runInContext", class: "vm", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
|
|
11054
11056
|
{ method: "runInNewContext", class: "vm", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
|
|
11055
11057
|
{ method: "runInThisContext", class: "vm", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
|
|
11058
|
+
{ method: "parse", class: "protobuf", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
11059
|
+
{ method: "parse", class: "protobufjs", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
11060
|
+
{ method: "parse", class: "Root", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
11056
11061
|
{ method: "find", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0] },
|
|
11057
11062
|
{ method: "findOne", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0] },
|
|
11058
11063
|
{ method: "updateOne", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0] },
|
|
@@ -12249,6 +12254,9 @@ function matchesSinkPattern(call, pattern, typeHierarchy, language) {
|
|
|
12249
12254
|
if (typeHierarchy && typeHierarchy.couldBeType(call.receiver, pattern.class)) {
|
|
12250
12255
|
return true;
|
|
12251
12256
|
}
|
|
12257
|
+
if (pattern.allow_unresolved_receiver && !call.receiver_type && !call.receiver_type_fqn && call.receiver.includes(".")) {
|
|
12258
|
+
return true;
|
|
12259
|
+
}
|
|
12252
12260
|
return false;
|
|
12253
12261
|
} else if (!call.receiver && !call.receiver_type) {
|
|
12254
12262
|
const target = call.resolution?.target;
|
|
@@ -15265,6 +15273,9 @@ class DefaultLanguageRegistry {
|
|
|
15265
15273
|
if (language === "tsx") {
|
|
15266
15274
|
return this.plugins.get("javascript");
|
|
15267
15275
|
}
|
|
15276
|
+
if (language === "typescript") {
|
|
15277
|
+
return this.plugins.get("javascript");
|
|
15278
|
+
}
|
|
15268
15279
|
return this.plugins.get(language);
|
|
15269
15280
|
}
|
|
15270
15281
|
getForFile(filePath) {
|
|
@@ -19080,10 +19091,26 @@ class CrossFileResolver {
|
|
|
19080
19091
|
}
|
|
19081
19092
|
resolveWithReceiver(call, fromFile) {
|
|
19082
19093
|
const receiver = call.receiver;
|
|
19083
|
-
const receiverType = this.inferReceiverType(receiver, fromFile);
|
|
19094
|
+
const receiverType = call.receiver_type_fqn ?? this.inferReceiverType(receiver, fromFile);
|
|
19084
19095
|
if (receiverType) {
|
|
19085
19096
|
const methodSymbol = this.symbolTable.findMethod(receiverType, call.method_name);
|
|
19086
19097
|
if (methodSymbol) {
|
|
19098
|
+
const parent = methodSymbol.parentType ? this.symbolTable.getSymbol(methodSymbol.parentType) : undefined;
|
|
19099
|
+
if (parent && parent.kind === "interface") {
|
|
19100
|
+
const candidates2 = this.findPolymorphicCandidates(receiverType, call.method_name);
|
|
19101
|
+
if (candidates2.length > 0) {
|
|
19102
|
+
const primary = candidates2[0];
|
|
19103
|
+
return {
|
|
19104
|
+
call,
|
|
19105
|
+
sourceFile: fromFile,
|
|
19106
|
+
targetFile: primary.file,
|
|
19107
|
+
targetMethod: primary.fqn,
|
|
19108
|
+
targetClass: primary.parentType || receiverType,
|
|
19109
|
+
resolution: "polymorphic",
|
|
19110
|
+
candidates: candidates2.map((c) => c.fqn)
|
|
19111
|
+
};
|
|
19112
|
+
}
|
|
19113
|
+
}
|
|
19087
19114
|
return {
|
|
19088
19115
|
call,
|
|
19089
19116
|
sourceFile: fromFile,
|
|
@@ -20096,7 +20123,8 @@ class CrossFilePass {
|
|
|
20096
20123
|
});
|
|
20097
20124
|
const ipPaths = [
|
|
20098
20125
|
...resolver.findInterproceduralTaintPaths(),
|
|
20099
|
-
...resolver.findFieldBindingTaintPaths()
|
|
20126
|
+
...resolver.findFieldBindingTaintPaths(),
|
|
20127
|
+
...findCrossInstanceAliasingPaths(projectGraph, sourceLines)
|
|
20100
20128
|
];
|
|
20101
20129
|
for (let i2 = 0;i2 < ipPaths.length; i2++) {
|
|
20102
20130
|
const p = ipPaths[i2];
|
|
@@ -20172,6 +20200,108 @@ class CrossFilePass {
|
|
|
20172
20200
|
return { crossFileCalls, taintPaths, typeHierarchy };
|
|
20173
20201
|
}
|
|
20174
20202
|
}
|
|
20203
|
+
function findCrossInstanceAliasingPaths(projectGraph, _sourceLines) {
|
|
20204
|
+
const paths = [];
|
|
20205
|
+
const javaHttpPattern = /\b(?:req|request|httpRequest|servletRequest|httpServletRequest)\.(?:getParameter|getParameterValues|getParameterMap|getHeader|getHeaders|getCookies|getQueryString|getPathInfo|getRequestURI|getRequestURL|getInputStream|getReader)\b/;
|
|
20206
|
+
const aliasWriteRe = /^\s*this\.([A-Za-z_]\w*)\.([A-Za-z_]\w*)\s*=\s*(.+?)(?:;\s*)?$/;
|
|
20207
|
+
const typeIndex = new Map;
|
|
20208
|
+
for (const filePath of projectGraph.filePaths) {
|
|
20209
|
+
const ir = projectGraph.getIR(filePath);
|
|
20210
|
+
if (!ir)
|
|
20211
|
+
continue;
|
|
20212
|
+
if (ir.meta.language !== "java")
|
|
20213
|
+
continue;
|
|
20214
|
+
for (const t of ir.types) {
|
|
20215
|
+
if (t.kind === "class")
|
|
20216
|
+
typeIndex.set(t.name, { file: filePath, type: t, ir });
|
|
20217
|
+
}
|
|
20218
|
+
}
|
|
20219
|
+
if (typeIndex.size === 0)
|
|
20220
|
+
return paths;
|
|
20221
|
+
for (const filePath of projectGraph.filePaths) {
|
|
20222
|
+
const ir = projectGraph.getIR(filePath);
|
|
20223
|
+
if (!ir)
|
|
20224
|
+
continue;
|
|
20225
|
+
if (ir.meta.language !== "java")
|
|
20226
|
+
continue;
|
|
20227
|
+
const lines = _sourceLines.get(filePath);
|
|
20228
|
+
if (!lines || lines.length === 0)
|
|
20229
|
+
continue;
|
|
20230
|
+
for (const type of ir.types) {
|
|
20231
|
+
if (type.kind !== "class")
|
|
20232
|
+
continue;
|
|
20233
|
+
const aliasFields = new Map;
|
|
20234
|
+
for (const f of type.fields) {
|
|
20235
|
+
if (!f.type)
|
|
20236
|
+
continue;
|
|
20237
|
+
const simple = f.type.replace(/<.*>/g, "").replace(/\[\]$/, "").trim();
|
|
20238
|
+
if (typeIndex.has(simple))
|
|
20239
|
+
aliasFields.set(f.name, simple);
|
|
20240
|
+
}
|
|
20241
|
+
if (aliasFields.size === 0)
|
|
20242
|
+
continue;
|
|
20243
|
+
for (const m of type.methods) {
|
|
20244
|
+
if (m.name === type.name)
|
|
20245
|
+
continue;
|
|
20246
|
+
const mStart = m.start_line;
|
|
20247
|
+
const mEnd = m.end_line;
|
|
20248
|
+
for (let i2 = mStart - 1;i2 < Math.min(mEnd, lines.length); i2++) {
|
|
20249
|
+
const trimmed = (lines[i2] ?? "").trim();
|
|
20250
|
+
if (!trimmed || trimmed.startsWith("//"))
|
|
20251
|
+
continue;
|
|
20252
|
+
const wm = trimmed.match(aliasWriteRe);
|
|
20253
|
+
if (!wm)
|
|
20254
|
+
continue;
|
|
20255
|
+
const aliasField = wm[1];
|
|
20256
|
+
const innerField = wm[2];
|
|
20257
|
+
const rhs = wm[3].trim().replace(/;\s*$/, "");
|
|
20258
|
+
const aliasType = aliasFields.get(aliasField);
|
|
20259
|
+
if (!aliasType)
|
|
20260
|
+
continue;
|
|
20261
|
+
const target = typeIndex.get(aliasType);
|
|
20262
|
+
if (!target)
|
|
20263
|
+
continue;
|
|
20264
|
+
if (!target.type.fields.some((f) => f.name === innerField))
|
|
20265
|
+
continue;
|
|
20266
|
+
if (!javaHttpPattern.test(rhs))
|
|
20267
|
+
continue;
|
|
20268
|
+
const innerRe = new RegExp(`\\b${innerField}\\b`);
|
|
20269
|
+
for (const tm of target.type.methods) {
|
|
20270
|
+
const sinksInTarget = target.ir.taint.sinks.filter((s) => s.line >= tm.start_line && s.line <= tm.end_line);
|
|
20271
|
+
for (const sink of sinksInTarget) {
|
|
20272
|
+
const callsAtSink = target.ir.calls.filter((c) => c.location.line === sink.line);
|
|
20273
|
+
let matched = false;
|
|
20274
|
+
for (const c of callsAtSink) {
|
|
20275
|
+
for (const a of c.arguments ?? []) {
|
|
20276
|
+
if (innerRe.test(a.expression ?? "") || a.variable === innerField) {
|
|
20277
|
+
matched = true;
|
|
20278
|
+
break;
|
|
20279
|
+
}
|
|
20280
|
+
}
|
|
20281
|
+
if (matched)
|
|
20282
|
+
break;
|
|
20283
|
+
}
|
|
20284
|
+
if (!matched)
|
|
20285
|
+
continue;
|
|
20286
|
+
paths.push({
|
|
20287
|
+
source: { file: filePath, line: i2 + 1, type: "http_param" },
|
|
20288
|
+
sink: { file: target.file, line: sink.line, type: sink.type, cwe: sink.cwe },
|
|
20289
|
+
hops: [
|
|
20290
|
+
{ file: filePath, line: i2 + 1, method: m.name, kind: "source" },
|
|
20291
|
+
{ file: filePath, line: i2 + 1, method: m.name, kind: "field_write" },
|
|
20292
|
+
{ file: target.file, line: tm.start_line, method: tm.name, kind: "field_read" },
|
|
20293
|
+
{ file: target.file, line: sink.line, method: tm.name, kind: "sink" }
|
|
20294
|
+
],
|
|
20295
|
+
confidence: 0.65
|
|
20296
|
+
});
|
|
20297
|
+
}
|
|
20298
|
+
}
|
|
20299
|
+
}
|
|
20300
|
+
}
|
|
20301
|
+
}
|
|
20302
|
+
}
|
|
20303
|
+
return paths;
|
|
20304
|
+
}
|
|
20175
20305
|
|
|
20176
20306
|
// ../circle-ir/dist/analysis/html/html-extractor.js
|
|
20177
20307
|
var EVENT_HANDLER_ATTRS = new Set([
|
|
@@ -20878,6 +21008,8 @@ class LanguageSourcesPass {
|
|
|
20878
21008
|
const additionalSanitizers = [];
|
|
20879
21009
|
additionalSources.push(...findGetterSources(types, constProp.instanceFieldTaint, code));
|
|
20880
21010
|
additionalSources.push(...findOopFieldReadSources(types, code, language));
|
|
21011
|
+
additionalSources.push(...findStaticFieldSources(types, code, language));
|
|
21012
|
+
additionalSources.push(...findSetterChainSources(types, code, language));
|
|
20881
21013
|
additionalSources.push(...findJavaScriptAssignmentSources(code, language));
|
|
20882
21014
|
const jsDOMSinks = findJavaScriptDOMSinks(code, language);
|
|
20883
21015
|
for (const s of jsDOMSinks) {
|
|
@@ -21106,6 +21238,155 @@ function findOopFieldReadSources(types, sourceCode, language) {
|
|
|
21106
21238
|
}
|
|
21107
21239
|
return sources;
|
|
21108
21240
|
}
|
|
21241
|
+
function findStaticFieldSources(types, sourceCode, language) {
|
|
21242
|
+
if (language !== "java")
|
|
21243
|
+
return [];
|
|
21244
|
+
const sources = [];
|
|
21245
|
+
const lines = sourceCode.split(`
|
|
21246
|
+
`);
|
|
21247
|
+
const javaHttpPattern = /\b(?:req|request|httpRequest|servletRequest|httpServletRequest)\.(?:getParameter|getParameterValues|getParameterMap|getHeader|getHeaders|getCookies|getQueryString|getPathInfo|getRequestURI|getRequestURL|getInputStream|getReader)\b/;
|
|
21248
|
+
for (const type of types) {
|
|
21249
|
+
if (type.kind !== "class")
|
|
21250
|
+
continue;
|
|
21251
|
+
if (type.name === "<module>")
|
|
21252
|
+
continue;
|
|
21253
|
+
const staticFields = new Set;
|
|
21254
|
+
for (const f of type.fields) {
|
|
21255
|
+
if (f.modifiers.includes("static"))
|
|
21256
|
+
staticFields.add(f.name);
|
|
21257
|
+
}
|
|
21258
|
+
if (staticFields.size === 0)
|
|
21259
|
+
continue;
|
|
21260
|
+
const qualifiedAssignRe = new RegExp(`^\\s*${type.name}\\.([A-Za-z_]\\w*)\\s*=\\s*(.+?)(?:;\\s*)?$`);
|
|
21261
|
+
const bareAssignRe = /^\s*([A-Za-z_]\w*)\s*=\s*(.+?)(?:;\s*)?$/;
|
|
21262
|
+
for (const m of type.methods) {
|
|
21263
|
+
if (!m.modifiers.includes("static"))
|
|
21264
|
+
continue;
|
|
21265
|
+
const mStart = m.start_line;
|
|
21266
|
+
const mEnd = m.end_line;
|
|
21267
|
+
for (let i2 = mStart - 1;i2 < Math.min(mEnd, lines.length); i2++) {
|
|
21268
|
+
const line = lines[i2] ?? "";
|
|
21269
|
+
const trimmed = line.trim();
|
|
21270
|
+
if (!trimmed || trimmed.startsWith("//"))
|
|
21271
|
+
continue;
|
|
21272
|
+
let fieldName = null;
|
|
21273
|
+
let rhs = null;
|
|
21274
|
+
const qm = trimmed.match(qualifiedAssignRe);
|
|
21275
|
+
if (qm) {
|
|
21276
|
+
fieldName = qm[1];
|
|
21277
|
+
rhs = qm[2];
|
|
21278
|
+
} else {
|
|
21279
|
+
const bm = trimmed.match(bareAssignRe);
|
|
21280
|
+
if (bm) {
|
|
21281
|
+
fieldName = bm[1];
|
|
21282
|
+
rhs = bm[2];
|
|
21283
|
+
}
|
|
21284
|
+
}
|
|
21285
|
+
if (!fieldName || !rhs)
|
|
21286
|
+
continue;
|
|
21287
|
+
if (!staticFields.has(fieldName))
|
|
21288
|
+
continue;
|
|
21289
|
+
rhs = rhs.trim().replace(/;\s*$/, "");
|
|
21290
|
+
if (!javaHttpPattern.test(rhs))
|
|
21291
|
+
continue;
|
|
21292
|
+
sources.push({
|
|
21293
|
+
type: "http_param",
|
|
21294
|
+
location: `${type.name}.${fieldName} static field set in ${m.name}() — #78 round 2`,
|
|
21295
|
+
severity: "high",
|
|
21296
|
+
line: i2 + 1,
|
|
21297
|
+
confidence: 0.85,
|
|
21298
|
+
variable: fieldName
|
|
21299
|
+
});
|
|
21300
|
+
sources.push({
|
|
21301
|
+
type: "http_param",
|
|
21302
|
+
location: `${type.name}.${fieldName} static field (qualified read alias) — #78 round 2`,
|
|
21303
|
+
severity: "high",
|
|
21304
|
+
line: i2 + 1,
|
|
21305
|
+
confidence: 0.85,
|
|
21306
|
+
variable: `${type.name}.${fieldName}`
|
|
21307
|
+
});
|
|
21308
|
+
}
|
|
21309
|
+
}
|
|
21310
|
+
}
|
|
21311
|
+
return sources;
|
|
21312
|
+
}
|
|
21313
|
+
function findSetterChainSources(types, sourceCode, language) {
|
|
21314
|
+
if (language !== "java")
|
|
21315
|
+
return [];
|
|
21316
|
+
const sources = [];
|
|
21317
|
+
const lines = sourceCode.split(`
|
|
21318
|
+
`);
|
|
21319
|
+
const javaHttpPattern = /\b(?:req|request|httpRequest|servletRequest|httpServletRequest)\.(?:getParameter|getParameterValues|getParameterMap|getHeader|getHeaders|getCookies|getQueryString|getPathInfo|getRequestURI|getRequestURL|getInputStream|getReader)\b/;
|
|
21320
|
+
for (const type of types) {
|
|
21321
|
+
if (type.kind !== "class")
|
|
21322
|
+
continue;
|
|
21323
|
+
if (type.name === "<module>")
|
|
21324
|
+
continue;
|
|
21325
|
+
const pairs = new Map;
|
|
21326
|
+
const setterRe = /this\.([A-Za-z_]\w*)\s*=\s*([A-Za-z_]\w*)\s*;?/;
|
|
21327
|
+
const getterRe = /return\s+this\.([A-Za-z_]\w*)\s*;?/;
|
|
21328
|
+
for (const m of type.methods) {
|
|
21329
|
+
if (m.name === type.name)
|
|
21330
|
+
continue;
|
|
21331
|
+
const mStart = m.start_line;
|
|
21332
|
+
const mEnd = m.end_line;
|
|
21333
|
+
const fullBody = lines.slice(mStart - 1, Math.min(mEnd, lines.length)).join(`
|
|
21334
|
+
`);
|
|
21335
|
+
const open = fullBody.indexOf("{");
|
|
21336
|
+
const close = fullBody.lastIndexOf("}");
|
|
21337
|
+
if (open < 0 || close < 0 || close <= open)
|
|
21338
|
+
continue;
|
|
21339
|
+
const inner = fullBody.slice(open + 1, close).replace(/\/\/[^\n]*/g, "").trim();
|
|
21340
|
+
if (!inner)
|
|
21341
|
+
continue;
|
|
21342
|
+
const sm = inner.match(setterRe);
|
|
21343
|
+
if (sm && m.parameters.length === 1 && sm[2] === m.parameters[0].name) {
|
|
21344
|
+
const remainder = inner.replace(sm[0], "").trim();
|
|
21345
|
+
if (!remainder) {
|
|
21346
|
+
const entry = pairs.get(sm[1]) ?? {};
|
|
21347
|
+
entry.setter = m.name;
|
|
21348
|
+
pairs.set(sm[1], entry);
|
|
21349
|
+
continue;
|
|
21350
|
+
}
|
|
21351
|
+
}
|
|
21352
|
+
const gm = inner.match(getterRe);
|
|
21353
|
+
if (gm && m.parameters.length === 0) {
|
|
21354
|
+
const remainder = inner.replace(gm[0], "").trim();
|
|
21355
|
+
if (!remainder) {
|
|
21356
|
+
const entry = pairs.get(gm[1]) ?? {};
|
|
21357
|
+
entry.getter = m.name;
|
|
21358
|
+
pairs.set(gm[1], entry);
|
|
21359
|
+
}
|
|
21360
|
+
}
|
|
21361
|
+
}
|
|
21362
|
+
for (const [, { setter, getter }] of pairs) {
|
|
21363
|
+
if (!setter || !getter)
|
|
21364
|
+
continue;
|
|
21365
|
+
const setterCallRe = new RegExp(`\\b([A-Za-z_]\\w*)\\.${setter}\\s*\\(\\s*([^)]+?)\\s*\\)\\s*;?`);
|
|
21366
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
21367
|
+
const line = lines[i2] ?? "";
|
|
21368
|
+
const trimmed = line.trim();
|
|
21369
|
+
if (!trimmed || trimmed.startsWith("//"))
|
|
21370
|
+
continue;
|
|
21371
|
+
const cm = trimmed.match(setterCallRe);
|
|
21372
|
+
if (!cm)
|
|
21373
|
+
continue;
|
|
21374
|
+
const arg = cm[2];
|
|
21375
|
+
if (!javaHttpPattern.test(arg))
|
|
21376
|
+
continue;
|
|
21377
|
+
sources.push({
|
|
21378
|
+
type: "http_param",
|
|
21379
|
+
location: `${type.name}.${setter}(tainted) → ${type.name}.${getter}() chain — #78 round 2`,
|
|
21380
|
+
severity: "high",
|
|
21381
|
+
line: i2 + 1,
|
|
21382
|
+
confidence: 0.75,
|
|
21383
|
+
variable: getter
|
|
21384
|
+
});
|
|
21385
|
+
}
|
|
21386
|
+
}
|
|
21387
|
+
}
|
|
21388
|
+
return sources;
|
|
21389
|
+
}
|
|
21109
21390
|
function findJavaScriptAssignmentSources(sourceCode, language) {
|
|
21110
21391
|
if (!["javascript", "typescript"].includes(language))
|
|
21111
21392
|
return [];
|
|
@@ -21852,6 +22133,32 @@ class SinkFilterPass {
|
|
|
21852
22133
|
return true;
|
|
21853
22134
|
});
|
|
21854
22135
|
}
|
|
22136
|
+
if (["javascript", "typescript"].includes(language)) {
|
|
22137
|
+
const sourceLines = ctx.code.split(`
|
|
22138
|
+
`);
|
|
22139
|
+
const guardPatterns = /\b(?:includes|startsWith|endsWith|indexOf|test|match)\s*\(/;
|
|
22140
|
+
filtered = filtered.filter((sink) => {
|
|
22141
|
+
if (sink.type !== "open_redirect" && sink.type !== "crlf") {
|
|
22142
|
+
return true;
|
|
22143
|
+
}
|
|
22144
|
+
const sinkLineText = sourceLines[sink.line - 1] ?? "";
|
|
22145
|
+
const startLine = Math.max(0, sink.line - 7);
|
|
22146
|
+
for (let i2 = startLine;i2 < sink.line - 1; i2++) {
|
|
22147
|
+
const line = sourceLines[i2] ?? "";
|
|
22148
|
+
if (/\bif\s*\(/.test(line) && guardPatterns.test(line)) {
|
|
22149
|
+
return false;
|
|
22150
|
+
}
|
|
22151
|
+
}
|
|
22152
|
+
if (/\bencodeURIComponent\s*\(|\bencodeURI\s*\(/.test(sinkLineText)) {
|
|
22153
|
+
return false;
|
|
22154
|
+
}
|
|
22155
|
+
const setHeaderMatch = sinkLineText.match(/setHeader\s*\(\s*[^,]+,\s*(['"`])([^'"`]*)\1\s*\)/);
|
|
22156
|
+
if (setHeaderMatch) {
|
|
22157
|
+
return false;
|
|
22158
|
+
}
|
|
22159
|
+
return true;
|
|
22160
|
+
});
|
|
22161
|
+
}
|
|
21855
22162
|
return { sources, sinks: filtered, sanitizers };
|
|
21856
22163
|
}
|
|
21857
22164
|
}
|
|
@@ -31047,7 +31354,7 @@ var colors = {
|
|
|
31047
31354
|
};
|
|
31048
31355
|
|
|
31049
31356
|
// src/version.ts
|
|
31050
|
-
var version = "3.
|
|
31357
|
+
var version = "3.67.0";
|
|
31051
31358
|
|
|
31052
31359
|
// src/formatters.ts
|
|
31053
31360
|
var SINK_SEVERITY = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.67.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.67.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/node": "^25.5.0",
|