cognium-dev 3.154.0 → 3.156.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 +469 -14
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -11659,6 +11659,7 @@ var DEFAULT_SANITIZERS = [
|
|
|
11659
11659
|
{ method: "parseDouble", class: "Double", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11660
11660
|
{ method: "parseShort", class: "Short", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11661
11661
|
{ method: "parseByte", class: "Byte", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11662
|
+
{ method: "parseBoolean", class: "Boolean", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection", "xss", "crlf", "log_injection", "xpath_injection", "ldap_injection", "xxe"] },
|
|
11662
11663
|
{ method: "fromString", class: "UUID", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11663
11664
|
{ method: "BigInt", removes: ["sql_injection", "nosql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11664
11665
|
{ method: "Atoi", class: "strconv", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
@@ -12977,7 +12978,8 @@ function matchesSinkPattern(call, pattern, typeHierarchy, language) {
|
|
|
12977
12978
|
if (pattern.class === "constructor") {
|
|
12978
12979
|
return true;
|
|
12979
12980
|
}
|
|
12980
|
-
|
|
12981
|
+
const subtypeArgArityOk = !pattern.arg_positions || pattern.arg_positions.length === 0 || pattern.arg_positions.every((pos) => pos < (call.arguments?.length ?? 0));
|
|
12982
|
+
if (call.receiver_type && call.receiver_type === pattern.class) {} else if (call.receiver_type && typeHierarchy && subtypeArgArityOk && typeHierarchy.isSubtypeOf(call.receiver_type, pattern.class)) {} else if (call.receiver_type_fqn && call.receiver_type_fqn.endsWith("." + pattern.class)) {} else if (call.receiver_type_fqn && typeHierarchy && subtypeArgArityOk && typeHierarchy.isSubtypeOf(call.receiver_type_fqn, pattern.class)) {} else if (call.receiver && !receiverMightBeClass(call.receiver, pattern.class)) {
|
|
12981
12983
|
if (typeHierarchy && typeHierarchy.couldBeType(call.receiver, pattern.class)) {
|
|
12982
12984
|
return true;
|
|
12983
12985
|
}
|
|
@@ -13770,6 +13772,18 @@ class CodeGraph {
|
|
|
13770
13772
|
}
|
|
13771
13773
|
return this._chainsByFromDef;
|
|
13772
13774
|
}
|
|
13775
|
+
_chainsByToDef = null;
|
|
13776
|
+
get chainsByToDef() {
|
|
13777
|
+
if (!this._chainsByToDef) {
|
|
13778
|
+
this._chainsByToDef = new Map;
|
|
13779
|
+
for (const chain of this.ir.dfg.chains ?? []) {
|
|
13780
|
+
const arr = this._chainsByToDef.get(chain.to_def) ?? [];
|
|
13781
|
+
arr.push(chain);
|
|
13782
|
+
this._chainsByToDef.set(chain.to_def, arr);
|
|
13783
|
+
}
|
|
13784
|
+
}
|
|
13785
|
+
return this._chainsByToDef;
|
|
13786
|
+
}
|
|
13773
13787
|
_callsByLine = null;
|
|
13774
13788
|
get callsByLine() {
|
|
13775
13789
|
if (!this._callsByLine) {
|
|
@@ -14303,8 +14317,150 @@ function createWithJdkTypes() {
|
|
|
14303
14317
|
for (const type of [...jdbcTypes, ...ioTypes, ...servletTypes]) {
|
|
14304
14318
|
resolver.addType(type, "jdk", type.package);
|
|
14305
14319
|
}
|
|
14320
|
+
registerCommonLibraries(resolver);
|
|
14306
14321
|
return resolver;
|
|
14307
14322
|
}
|
|
14323
|
+
function registerCommonLibraries(resolver) {
|
|
14324
|
+
const apacheHttpClient4x = [
|
|
14325
|
+
{
|
|
14326
|
+
name: "HttpClient",
|
|
14327
|
+
kind: "interface",
|
|
14328
|
+
package: "org.apache.http.client",
|
|
14329
|
+
extends: null,
|
|
14330
|
+
implements: [],
|
|
14331
|
+
annotations: [],
|
|
14332
|
+
methods: [],
|
|
14333
|
+
fields: [],
|
|
14334
|
+
start_line: 0,
|
|
14335
|
+
end_line: 0
|
|
14336
|
+
},
|
|
14337
|
+
{
|
|
14338
|
+
name: "AbstractHttpClient",
|
|
14339
|
+
kind: "class",
|
|
14340
|
+
package: "org.apache.http.impl.client",
|
|
14341
|
+
extends: null,
|
|
14342
|
+
implements: ["org.apache.http.client.HttpClient"],
|
|
14343
|
+
annotations: [],
|
|
14344
|
+
methods: [],
|
|
14345
|
+
fields: [],
|
|
14346
|
+
start_line: 0,
|
|
14347
|
+
end_line: 0
|
|
14348
|
+
},
|
|
14349
|
+
{
|
|
14350
|
+
name: "CloseableHttpClient",
|
|
14351
|
+
kind: "class",
|
|
14352
|
+
package: "org.apache.http.impl.client",
|
|
14353
|
+
extends: null,
|
|
14354
|
+
implements: ["org.apache.http.client.HttpClient"],
|
|
14355
|
+
annotations: [],
|
|
14356
|
+
methods: [],
|
|
14357
|
+
fields: [],
|
|
14358
|
+
start_line: 0,
|
|
14359
|
+
end_line: 0
|
|
14360
|
+
},
|
|
14361
|
+
{
|
|
14362
|
+
name: "InternalHttpClient",
|
|
14363
|
+
kind: "class",
|
|
14364
|
+
package: "org.apache.http.impl.client",
|
|
14365
|
+
extends: "org.apache.http.impl.client.CloseableHttpClient",
|
|
14366
|
+
implements: [],
|
|
14367
|
+
annotations: [],
|
|
14368
|
+
methods: [],
|
|
14369
|
+
fields: [],
|
|
14370
|
+
start_line: 0,
|
|
14371
|
+
end_line: 0
|
|
14372
|
+
},
|
|
14373
|
+
{
|
|
14374
|
+
name: "MinimalHttpClient",
|
|
14375
|
+
kind: "class",
|
|
14376
|
+
package: "org.apache.http.impl.client",
|
|
14377
|
+
extends: "org.apache.http.impl.client.CloseableHttpClient",
|
|
14378
|
+
implements: [],
|
|
14379
|
+
annotations: [],
|
|
14380
|
+
methods: [],
|
|
14381
|
+
fields: [],
|
|
14382
|
+
start_line: 0,
|
|
14383
|
+
end_line: 0
|
|
14384
|
+
},
|
|
14385
|
+
{
|
|
14386
|
+
name: "DefaultHttpClient",
|
|
14387
|
+
kind: "class",
|
|
14388
|
+
package: "org.apache.http.impl.client",
|
|
14389
|
+
extends: "org.apache.http.impl.client.AbstractHttpClient",
|
|
14390
|
+
implements: [],
|
|
14391
|
+
annotations: [],
|
|
14392
|
+
methods: [],
|
|
14393
|
+
fields: [],
|
|
14394
|
+
start_line: 0,
|
|
14395
|
+
end_line: 0
|
|
14396
|
+
},
|
|
14397
|
+
{
|
|
14398
|
+
name: "SystemDefaultHttpClient",
|
|
14399
|
+
kind: "class",
|
|
14400
|
+
package: "org.apache.http.impl.client",
|
|
14401
|
+
extends: "org.apache.http.impl.client.DefaultHttpClient",
|
|
14402
|
+
implements: [],
|
|
14403
|
+
annotations: [],
|
|
14404
|
+
methods: [],
|
|
14405
|
+
fields: [],
|
|
14406
|
+
start_line: 0,
|
|
14407
|
+
end_line: 0
|
|
14408
|
+
}
|
|
14409
|
+
];
|
|
14410
|
+
const apacheHttpClient5x = [
|
|
14411
|
+
{
|
|
14412
|
+
name: "HttpClient",
|
|
14413
|
+
kind: "interface",
|
|
14414
|
+
package: "org.apache.hc.client5.http.classic",
|
|
14415
|
+
extends: null,
|
|
14416
|
+
implements: [],
|
|
14417
|
+
annotations: [],
|
|
14418
|
+
methods: [],
|
|
14419
|
+
fields: [],
|
|
14420
|
+
start_line: 0,
|
|
14421
|
+
end_line: 0
|
|
14422
|
+
},
|
|
14423
|
+
{
|
|
14424
|
+
name: "CloseableHttpClient",
|
|
14425
|
+
kind: "class",
|
|
14426
|
+
package: "org.apache.hc.client5.http.impl.classic",
|
|
14427
|
+
extends: null,
|
|
14428
|
+
implements: ["org.apache.hc.client5.http.classic.HttpClient"],
|
|
14429
|
+
annotations: [],
|
|
14430
|
+
methods: [],
|
|
14431
|
+
fields: [],
|
|
14432
|
+
start_line: 0,
|
|
14433
|
+
end_line: 0
|
|
14434
|
+
},
|
|
14435
|
+
{
|
|
14436
|
+
name: "InternalHttpClient",
|
|
14437
|
+
kind: "class",
|
|
14438
|
+
package: "org.apache.hc.client5.http.impl.classic",
|
|
14439
|
+
extends: "org.apache.hc.client5.http.impl.classic.CloseableHttpClient",
|
|
14440
|
+
implements: [],
|
|
14441
|
+
annotations: [],
|
|
14442
|
+
methods: [],
|
|
14443
|
+
fields: [],
|
|
14444
|
+
start_line: 0,
|
|
14445
|
+
end_line: 0
|
|
14446
|
+
},
|
|
14447
|
+
{
|
|
14448
|
+
name: "MinimalHttpClient",
|
|
14449
|
+
kind: "class",
|
|
14450
|
+
package: "org.apache.hc.client5.http.impl.classic",
|
|
14451
|
+
extends: "org.apache.hc.client5.http.impl.classic.CloseableHttpClient",
|
|
14452
|
+
implements: [],
|
|
14453
|
+
annotations: [],
|
|
14454
|
+
methods: [],
|
|
14455
|
+
fields: [],
|
|
14456
|
+
start_line: 0,
|
|
14457
|
+
end_line: 0
|
|
14458
|
+
}
|
|
14459
|
+
];
|
|
14460
|
+
for (const type of [...apacheHttpClient4x, ...apacheHttpClient5x]) {
|
|
14461
|
+
resolver.addType(type, "common-libraries", type.package);
|
|
14462
|
+
}
|
|
14463
|
+
}
|
|
14308
14464
|
// ../circle-ir/dist/resolution/symbol-table.js
|
|
14309
14465
|
class SymbolTable {
|
|
14310
14466
|
exports = new Map;
|
|
@@ -15640,6 +15796,45 @@ class AnalysisPipeline {
|
|
|
15640
15796
|
return { results, findings };
|
|
15641
15797
|
}
|
|
15642
15798
|
}
|
|
15799
|
+
// ../circle-ir/dist/analysis/dfg-walk.js
|
|
15800
|
+
function walkBackwardDefs(startDefId, chainsByToDef, defById, options = {}) {
|
|
15801
|
+
const maxHops = options.maxHops ?? 32;
|
|
15802
|
+
const visited = new Set;
|
|
15803
|
+
const lines = new Set;
|
|
15804
|
+
let hopCapReached = false;
|
|
15805
|
+
const startDef = defById.get(startDefId);
|
|
15806
|
+
if (!startDef) {
|
|
15807
|
+
return { visited, lines, hopCapReached: false };
|
|
15808
|
+
}
|
|
15809
|
+
visited.add(startDefId);
|
|
15810
|
+
lines.add(startDef.line);
|
|
15811
|
+
const queue = [startDefId];
|
|
15812
|
+
let hops = 0;
|
|
15813
|
+
while (queue.length > 0) {
|
|
15814
|
+
if (hops >= maxHops) {
|
|
15815
|
+
hopCapReached = true;
|
|
15816
|
+
break;
|
|
15817
|
+
}
|
|
15818
|
+
hops++;
|
|
15819
|
+
const currentId = queue.shift();
|
|
15820
|
+
const incoming = chainsByToDef.get(currentId);
|
|
15821
|
+
if (!incoming)
|
|
15822
|
+
continue;
|
|
15823
|
+
for (const chain of incoming) {
|
|
15824
|
+
const fromId = chain.from_def;
|
|
15825
|
+
if (visited.has(fromId))
|
|
15826
|
+
continue;
|
|
15827
|
+
visited.add(fromId);
|
|
15828
|
+
const fromDef = defById.get(fromId);
|
|
15829
|
+
if (fromDef) {
|
|
15830
|
+
lines.add(fromDef.line);
|
|
15831
|
+
}
|
|
15832
|
+
queue.push(fromId);
|
|
15833
|
+
}
|
|
15834
|
+
}
|
|
15835
|
+
return { visited, lines, hopCapReached };
|
|
15836
|
+
}
|
|
15837
|
+
|
|
15643
15838
|
// ../circle-ir/dist/analysis/taint-propagation.js
|
|
15644
15839
|
function buildSanitizersByLine(sanitizers) {
|
|
15645
15840
|
const out2 = new Map;
|
|
@@ -15721,7 +15916,11 @@ function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanit
|
|
|
15721
15916
|
if (allTaintedDefIds.has(use.def_id)) {
|
|
15722
15917
|
const taintInfo = taintByDefId.get(use.def_id);
|
|
15723
15918
|
if (taintInfo) {
|
|
15724
|
-
const isSanitized = checkSanitized(taintInfo.line, sink.line, sink.type, sanitizersByLine
|
|
15919
|
+
const isSanitized = checkSanitized(taintInfo.line, sink.line, sink.type, sanitizersByLine, {
|
|
15920
|
+
startDefId: use.def_id,
|
|
15921
|
+
chainsByToDef: graph.chainsByToDef,
|
|
15922
|
+
defById
|
|
15923
|
+
});
|
|
15725
15924
|
if (!isSanitized.sanitized) {
|
|
15726
15925
|
const source = sources.find((s) => s.line === taintInfo.sourceLine);
|
|
15727
15926
|
if (source) {
|
|
@@ -15851,20 +16050,36 @@ var KNOWN_SINK_TYPES = new Set([
|
|
|
15851
16050
|
"crlf",
|
|
15852
16051
|
"mass_assignment"
|
|
15853
16052
|
]);
|
|
15854
|
-
function checkSanitized(_fromLine, toLine, sinkType, sanitizersByLine) {
|
|
15855
|
-
const sanitizersAtTarget = sanitizersByLine.get(toLine);
|
|
15856
|
-
if (!sanitizersAtTarget || sanitizersAtTarget.length === 0) {
|
|
15857
|
-
return { sanitized: false };
|
|
15858
|
-
}
|
|
16053
|
+
function checkSanitized(_fromLine, toLine, sinkType, sanitizersByLine, ctx) {
|
|
15859
16054
|
const isKnownSinkType = KNOWN_SINK_TYPES.has(sinkType);
|
|
15860
|
-
|
|
15861
|
-
|
|
15862
|
-
|
|
16055
|
+
const sanitizersAtTarget = sanitizersByLine.get(toLine);
|
|
16056
|
+
if (sanitizersAtTarget && sanitizersAtTarget.length > 0) {
|
|
16057
|
+
for (const san of sanitizersAtTarget) {
|
|
16058
|
+
if (isKnownSinkType) {
|
|
16059
|
+
if (san.sanitizes.includes(sinkType)) {
|
|
16060
|
+
return { sanitized: true, sanitizer: san };
|
|
16061
|
+
}
|
|
16062
|
+
} else if (san.sanitizes.length > 0) {
|
|
15863
16063
|
return { sanitized: true, sanitizer: san };
|
|
15864
16064
|
}
|
|
15865
|
-
}
|
|
15866
|
-
|
|
15867
|
-
|
|
16065
|
+
}
|
|
16066
|
+
}
|
|
16067
|
+
if (ctx) {
|
|
16068
|
+
const walk = walkBackwardDefs(ctx.startDefId, ctx.chainsByToDef, ctx.defById, { maxHops: ctx.maxHops ?? 32 });
|
|
16069
|
+
for (const line of walk.lines) {
|
|
16070
|
+
if (line === toLine)
|
|
16071
|
+
continue;
|
|
16072
|
+
const sansAtLine = sanitizersByLine.get(line);
|
|
16073
|
+
if (!sansAtLine || sansAtLine.length === 0)
|
|
16074
|
+
continue;
|
|
16075
|
+
for (const san of sansAtLine) {
|
|
16076
|
+
if (isKnownSinkType) {
|
|
16077
|
+
if (san.sanitizes.includes(sinkType)) {
|
|
16078
|
+
return { sanitized: true, sanitizer: san };
|
|
16079
|
+
}
|
|
16080
|
+
} else if (san.sanitizes.length > 0) {
|
|
16081
|
+
return { sanitized: true, sanitizer: san };
|
|
16082
|
+
}
|
|
15868
16083
|
}
|
|
15869
16084
|
}
|
|
15870
16085
|
}
|
|
@@ -24132,6 +24347,20 @@ function findJavaScriptDOMSinks(sourceCode, language) {
|
|
|
24132
24347
|
method = "cssText";
|
|
24133
24348
|
else if (line.includes("style.textContent"))
|
|
24134
24349
|
method = "textContent";
|
|
24350
|
+
if (method === "document.write" || method === "document.writeln") {
|
|
24351
|
+
const argMatch = line.match(/document\.write(?:ln)?\s*\(\s*([^)]*)\)/);
|
|
24352
|
+
if (argMatch) {
|
|
24353
|
+
const arg = argMatch[1].trim();
|
|
24354
|
+
if (!arg.includes("+")) {
|
|
24355
|
+
const doubleQ = /^"(?:[^"\\]|\\.)*"$/;
|
|
24356
|
+
const singleQ = /^'(?:[^'\\]|\\.)*'$/;
|
|
24357
|
+
const backtick = /^`(?:[^`\\$]|\\.|\$(?!\{))*`$/;
|
|
24358
|
+
if (doubleQ.test(arg) || singleQ.test(arg) || backtick.test(arg)) {
|
|
24359
|
+
break;
|
|
24360
|
+
}
|
|
24361
|
+
}
|
|
24362
|
+
}
|
|
24363
|
+
}
|
|
24135
24364
|
const alreadyExists = sinks.some((s) => s.line === lineNumber && s.cwe === cwe);
|
|
24136
24365
|
if (!alreadyExists) {
|
|
24137
24366
|
sinks.push({ type, cwe, severity, line: lineNumber, location: line.trim().substring(0, 80), method });
|
|
@@ -29405,6 +29634,202 @@ class LibraryProfileSourceGatePass {
|
|
|
29405
29634
|
}
|
|
29406
29635
|
}
|
|
29407
29636
|
|
|
29637
|
+
// ../circle-ir/dist/analysis/passes/mybatis-annotation-sql-sink-pass.js
|
|
29638
|
+
var MYBATIS_SQL_ANNOTATIONS = new Set([
|
|
29639
|
+
"Select",
|
|
29640
|
+
"Update",
|
|
29641
|
+
"Insert",
|
|
29642
|
+
"Delete",
|
|
29643
|
+
"SelectProvider",
|
|
29644
|
+
"UpdateProvider",
|
|
29645
|
+
"InsertProvider",
|
|
29646
|
+
"DeleteProvider"
|
|
29647
|
+
]);
|
|
29648
|
+
var DOLLAR_BRACE_RE = /\$\{([A-Za-z_][A-Za-z0-9_]*)(?:\.[A-Za-z0-9_.]+)?\}/g;
|
|
29649
|
+
function parsePositionalRef(name2) {
|
|
29650
|
+
const paramMatch = /^param(\d+)$/.exec(name2);
|
|
29651
|
+
if (paramMatch) {
|
|
29652
|
+
const oneBased = Number.parseInt(paramMatch[1], 10);
|
|
29653
|
+
if (Number.isFinite(oneBased) && oneBased >= 1)
|
|
29654
|
+
return oneBased - 1;
|
|
29655
|
+
}
|
|
29656
|
+
const zeroMatch = /^(\d+)$/.exec(name2);
|
|
29657
|
+
if (zeroMatch) {
|
|
29658
|
+
const zeroBased = Number.parseInt(zeroMatch[1], 10);
|
|
29659
|
+
if (Number.isFinite(zeroBased) && zeroBased >= 0)
|
|
29660
|
+
return zeroBased;
|
|
29661
|
+
}
|
|
29662
|
+
return null;
|
|
29663
|
+
}
|
|
29664
|
+
function extractAnnotationBody(annotation) {
|
|
29665
|
+
const openIdx = annotation.indexOf("(");
|
|
29666
|
+
if (openIdx < 0)
|
|
29667
|
+
return null;
|
|
29668
|
+
const closeIdx = annotation.lastIndexOf(")");
|
|
29669
|
+
if (closeIdx <= openIdx)
|
|
29670
|
+
return null;
|
|
29671
|
+
return annotation.substring(openIdx + 1, closeIdx);
|
|
29672
|
+
}
|
|
29673
|
+
function annotationName(annotation) {
|
|
29674
|
+
const openIdx = annotation.indexOf("(");
|
|
29675
|
+
return openIdx < 0 ? annotation : annotation.substring(0, openIdx);
|
|
29676
|
+
}
|
|
29677
|
+
function extractParamName(annotation) {
|
|
29678
|
+
if (annotationName(annotation) !== "Param")
|
|
29679
|
+
return null;
|
|
29680
|
+
const body2 = extractAnnotationBody(annotation);
|
|
29681
|
+
if (body2 === null)
|
|
29682
|
+
return null;
|
|
29683
|
+
const strMatch = /^\s*["']([^"']*)["']/.exec(body2);
|
|
29684
|
+
return strMatch ? strMatch[1] : null;
|
|
29685
|
+
}
|
|
29686
|
+
function extractDollarBraceRefs(annotationBody) {
|
|
29687
|
+
const seen = new Set;
|
|
29688
|
+
const out2 = [];
|
|
29689
|
+
DOLLAR_BRACE_RE.lastIndex = 0;
|
|
29690
|
+
let m;
|
|
29691
|
+
while ((m = DOLLAR_BRACE_RE.exec(annotationBody)) !== null) {
|
|
29692
|
+
const name2 = m[1];
|
|
29693
|
+
if (!seen.has(name2)) {
|
|
29694
|
+
seen.add(name2);
|
|
29695
|
+
out2.push(name2);
|
|
29696
|
+
}
|
|
29697
|
+
}
|
|
29698
|
+
return out2;
|
|
29699
|
+
}
|
|
29700
|
+
function fileImportsMyBatis(imports) {
|
|
29701
|
+
for (const imp of imports) {
|
|
29702
|
+
const pkg = imp.from_package;
|
|
29703
|
+
if (!pkg)
|
|
29704
|
+
continue;
|
|
29705
|
+
if (pkg === "org.apache.ibatis.annotations" || pkg.startsWith("org.apache.ibatis.annotations.") || pkg === "org.apache.ibatis" || pkg.startsWith("org.apache.ibatis.")) {
|
|
29706
|
+
return true;
|
|
29707
|
+
}
|
|
29708
|
+
}
|
|
29709
|
+
return false;
|
|
29710
|
+
}
|
|
29711
|
+
function correlateDollarBraceToArgPositions(method, refs) {
|
|
29712
|
+
const paramNameToIndex = new Map;
|
|
29713
|
+
method.parameters.forEach((param, idx) => {
|
|
29714
|
+
for (const ann of param.annotations) {
|
|
29715
|
+
const paramName = extractParamName(ann);
|
|
29716
|
+
if (paramName !== null) {
|
|
29717
|
+
paramNameToIndex.set(paramName, idx);
|
|
29718
|
+
}
|
|
29719
|
+
}
|
|
29720
|
+
});
|
|
29721
|
+
const positions = new Set;
|
|
29722
|
+
for (const ref of refs) {
|
|
29723
|
+
const namedIdx = paramNameToIndex.get(ref);
|
|
29724
|
+
if (namedIdx !== undefined) {
|
|
29725
|
+
positions.add(namedIdx);
|
|
29726
|
+
continue;
|
|
29727
|
+
}
|
|
29728
|
+
const positionalIdx = parsePositionalRef(ref);
|
|
29729
|
+
if (positionalIdx !== null && positionalIdx < method.parameters.length) {
|
|
29730
|
+
positions.add(positionalIdx);
|
|
29731
|
+
}
|
|
29732
|
+
}
|
|
29733
|
+
return Array.from(positions).sort((a, b) => a - b);
|
|
29734
|
+
}
|
|
29735
|
+
function isMapperMethodCall(call, interfaceSimpleName, interfaceFqn, methodName) {
|
|
29736
|
+
const target = call.resolution?.target;
|
|
29737
|
+
if (target) {
|
|
29738
|
+
const suffix = `${interfaceSimpleName}.${methodName}`;
|
|
29739
|
+
const suffixFqn = `${interfaceFqn}.${methodName}`;
|
|
29740
|
+
if (target === suffix || target === suffixFqn || target.endsWith("." + suffix) || target.endsWith("." + suffixFqn)) {
|
|
29741
|
+
return true;
|
|
29742
|
+
}
|
|
29743
|
+
}
|
|
29744
|
+
if (call.method_name !== methodName)
|
|
29745
|
+
return false;
|
|
29746
|
+
if (call.receiver_type === interfaceSimpleName)
|
|
29747
|
+
return true;
|
|
29748
|
+
if (call.receiver_type_fqn === interfaceFqn)
|
|
29749
|
+
return true;
|
|
29750
|
+
return false;
|
|
29751
|
+
}
|
|
29752
|
+
|
|
29753
|
+
class MyBatisAnnotationSqlSinkPass {
|
|
29754
|
+
name = "mybatis-annotation-sql-sink";
|
|
29755
|
+
category = "security";
|
|
29756
|
+
run(ctx) {
|
|
29757
|
+
if (ctx.language !== "java") {
|
|
29758
|
+
return { annotatedMethodCount: 0, addedSinkCount: 0 };
|
|
29759
|
+
}
|
|
29760
|
+
const { types, imports, calls } = ctx.graph.ir;
|
|
29761
|
+
if (!fileImportsMyBatis(imports)) {
|
|
29762
|
+
return { annotatedMethodCount: 0, addedSinkCount: 0 };
|
|
29763
|
+
}
|
|
29764
|
+
const mapperMethods = [];
|
|
29765
|
+
for (const type of types) {
|
|
29766
|
+
if (type.kind !== "interface")
|
|
29767
|
+
continue;
|
|
29768
|
+
for (const method of type.methods) {
|
|
29769
|
+
let matchedRefs = [];
|
|
29770
|
+
for (const ann of method.annotations) {
|
|
29771
|
+
if (!MYBATIS_SQL_ANNOTATIONS.has(annotationName(ann)))
|
|
29772
|
+
continue;
|
|
29773
|
+
const body2 = extractAnnotationBody(ann);
|
|
29774
|
+
if (body2 === null)
|
|
29775
|
+
continue;
|
|
29776
|
+
const refs = extractDollarBraceRefs(body2);
|
|
29777
|
+
if (refs.length > 0) {
|
|
29778
|
+
matchedRefs = [...matchedRefs, ...refs];
|
|
29779
|
+
}
|
|
29780
|
+
}
|
|
29781
|
+
if (matchedRefs.length === 0)
|
|
29782
|
+
continue;
|
|
29783
|
+
const positions = correlateDollarBraceToArgPositions(method, matchedRefs);
|
|
29784
|
+
if (positions.length === 0)
|
|
29785
|
+
continue;
|
|
29786
|
+
const interfaceFqn = type.package ? `${type.package}.${type.name}` : type.name;
|
|
29787
|
+
mapperMethods.push({
|
|
29788
|
+
interfaceSimpleName: type.name,
|
|
29789
|
+
interfaceFqn,
|
|
29790
|
+
methodName: method.name,
|
|
29791
|
+
taintedArgPositions: positions
|
|
29792
|
+
});
|
|
29793
|
+
}
|
|
29794
|
+
}
|
|
29795
|
+
if (mapperMethods.length === 0) {
|
|
29796
|
+
return {
|
|
29797
|
+
annotatedMethodCount: 0,
|
|
29798
|
+
addedSinkCount: 0
|
|
29799
|
+
};
|
|
29800
|
+
}
|
|
29801
|
+
const sinks = ctx.hasResult("taint-matcher") ? ctx.getResult("taint-matcher").sinks : ctx.graph.ir.taint.sinks;
|
|
29802
|
+
let addedSinkCount = 0;
|
|
29803
|
+
for (const call of calls) {
|
|
29804
|
+
for (const rec of mapperMethods) {
|
|
29805
|
+
if (!isMapperMethodCall(call, rec.interfaceSimpleName, rec.interfaceFqn, rec.methodName)) {
|
|
29806
|
+
continue;
|
|
29807
|
+
}
|
|
29808
|
+
const line = call.location.line;
|
|
29809
|
+
if (sinks.some((s) => s.line === line && s.type === "sql_injection" && s.method === rec.methodName)) {
|
|
29810
|
+
continue;
|
|
29811
|
+
}
|
|
29812
|
+
const receiverLoc = call.receiver ? `${call.receiver}.${rec.methodName}()` : `${rec.methodName}()`;
|
|
29813
|
+
sinks.push({
|
|
29814
|
+
type: "sql_injection",
|
|
29815
|
+
cwe: "CWE-89",
|
|
29816
|
+
location: call.in_method ? `${receiverLoc} in ${call.in_method}` : receiverLoc,
|
|
29817
|
+
line,
|
|
29818
|
+
confidence: 0.95,
|
|
29819
|
+
method: rec.methodName,
|
|
29820
|
+
argPositions: rec.taintedArgPositions,
|
|
29821
|
+
class: rec.interfaceSimpleName
|
|
29822
|
+
});
|
|
29823
|
+
addedSinkCount++;
|
|
29824
|
+
}
|
|
29825
|
+
}
|
|
29826
|
+
return {
|
|
29827
|
+
annotatedMethodCount: mapperMethods.length,
|
|
29828
|
+
addedSinkCount
|
|
29829
|
+
};
|
|
29830
|
+
}
|
|
29831
|
+
}
|
|
29832
|
+
|
|
29408
29833
|
// ../circle-ir/dist/analysis/passes/sink-filter-pass.js
|
|
29409
29834
|
var JS_XSS_SANITIZERS = [
|
|
29410
29835
|
/\bDOMPurify\.sanitize\s*\(/,
|
|
@@ -38207,6 +38632,31 @@ class WeakHashPass {
|
|
|
38207
38632
|
}
|
|
38208
38633
|
}
|
|
38209
38634
|
|
|
38635
|
+
// ../circle-ir/dist/analysis/path-classification.js
|
|
38636
|
+
var TEST_PATH_PATTERNS = [
|
|
38637
|
+
/(^|\/)test\//i,
|
|
38638
|
+
/(^|\/)tests\//i,
|
|
38639
|
+
/(^|\/)testing\//i,
|
|
38640
|
+
/(^|\/)__tests__\//i,
|
|
38641
|
+
/(^|\/)spec\//i,
|
|
38642
|
+
/_test\.go$/i,
|
|
38643
|
+
/(^|\/)test_[^/]+\.py$/i,
|
|
38644
|
+
/_test\.py$/i,
|
|
38645
|
+
/\.test\.(?:tsx?|jsx?|mjs|cjs)$/i,
|
|
38646
|
+
/\.spec\.(?:tsx?|jsx?|mjs|cjs)$/i,
|
|
38647
|
+
/\.test\.(?:java|kt)$/i
|
|
38648
|
+
];
|
|
38649
|
+
function isTestPath(filepath) {
|
|
38650
|
+
if (!filepath)
|
|
38651
|
+
return false;
|
|
38652
|
+
const normalized = filepath.replace(/\\/g, "/");
|
|
38653
|
+
for (const pattern of TEST_PATH_PATTERNS) {
|
|
38654
|
+
if (pattern.test(normalized))
|
|
38655
|
+
return true;
|
|
38656
|
+
}
|
|
38657
|
+
return false;
|
|
38658
|
+
}
|
|
38659
|
+
|
|
38210
38660
|
// ../circle-ir/dist/analysis/passes/weak-crypto-pass.js
|
|
38211
38661
|
var WEAK_CIPHER_BASES = new Set([
|
|
38212
38662
|
"des",
|
|
@@ -38422,6 +38872,9 @@ class WeakCryptoPass {
|
|
|
38422
38872
|
if (isProtocolMandatedCryptoFile(file, code)) {
|
|
38423
38873
|
return { findings: [] };
|
|
38424
38874
|
}
|
|
38875
|
+
if (isTestPath(file)) {
|
|
38876
|
+
return { findings: [] };
|
|
38877
|
+
}
|
|
38425
38878
|
const findings = [];
|
|
38426
38879
|
const constProp = ctx.hasResult("constant-propagation") ? ctx.getResult("constant-propagation") : null;
|
|
38427
38880
|
const literalBindings = scanLiteralBindings(code, language);
|
|
@@ -42180,6 +42633,8 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
42180
42633
|
pipeline.add(new SourceSemanticsPass);
|
|
42181
42634
|
if (!disabledPasses.has("library-profile-source-gate"))
|
|
42182
42635
|
pipeline.add(new LibraryProfileSourceGatePass);
|
|
42636
|
+
if (!disabledPasses.has("mybatis-annotation-sql-sink"))
|
|
42637
|
+
pipeline.add(new MyBatisAnnotationSqlSinkPass);
|
|
42183
42638
|
pipeline.add(new SinkFilterPass);
|
|
42184
42639
|
if (!disabledPasses.has("sink-semantics"))
|
|
42185
42640
|
pipeline.add(new SinkSemanticsPass);
|
|
@@ -43125,7 +43580,7 @@ var colors = {
|
|
|
43125
43580
|
};
|
|
43126
43581
|
|
|
43127
43582
|
// src/version.ts
|
|
43128
|
-
var version = "3.
|
|
43583
|
+
var version = "3.156.0";
|
|
43129
43584
|
|
|
43130
43585
|
// src/formatters.ts
|
|
43131
43586
|
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.156.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.156.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/node": "^25.5.0",
|