cognium-dev 3.155.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 +343 -2
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -12978,7 +12978,8 @@ function matchesSinkPattern(call, pattern, typeHierarchy, language) {
|
|
|
12978
12978
|
if (pattern.class === "constructor") {
|
|
12979
12979
|
return true;
|
|
12980
12980
|
}
|
|
12981
|
-
|
|
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)) {
|
|
12982
12983
|
if (typeHierarchy && typeHierarchy.couldBeType(call.receiver, pattern.class)) {
|
|
12983
12984
|
return true;
|
|
12984
12985
|
}
|
|
@@ -14316,8 +14317,150 @@ function createWithJdkTypes() {
|
|
|
14316
14317
|
for (const type of [...jdbcTypes, ...ioTypes, ...servletTypes]) {
|
|
14317
14318
|
resolver.addType(type, "jdk", type.package);
|
|
14318
14319
|
}
|
|
14320
|
+
registerCommonLibraries(resolver);
|
|
14319
14321
|
return resolver;
|
|
14320
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
|
+
}
|
|
14321
14464
|
// ../circle-ir/dist/resolution/symbol-table.js
|
|
14322
14465
|
class SymbolTable {
|
|
14323
14466
|
exports = new Map;
|
|
@@ -29491,6 +29634,202 @@ class LibraryProfileSourceGatePass {
|
|
|
29491
29634
|
}
|
|
29492
29635
|
}
|
|
29493
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
|
+
|
|
29494
29833
|
// ../circle-ir/dist/analysis/passes/sink-filter-pass.js
|
|
29495
29834
|
var JS_XSS_SANITIZERS = [
|
|
29496
29835
|
/\bDOMPurify\.sanitize\s*\(/,
|
|
@@ -42294,6 +42633,8 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
42294
42633
|
pipeline.add(new SourceSemanticsPass);
|
|
42295
42634
|
if (!disabledPasses.has("library-profile-source-gate"))
|
|
42296
42635
|
pipeline.add(new LibraryProfileSourceGatePass);
|
|
42636
|
+
if (!disabledPasses.has("mybatis-annotation-sql-sink"))
|
|
42637
|
+
pipeline.add(new MyBatisAnnotationSqlSinkPass);
|
|
42297
42638
|
pipeline.add(new SinkFilterPass);
|
|
42298
42639
|
if (!disabledPasses.has("sink-semantics"))
|
|
42299
42640
|
pipeline.add(new SinkSemanticsPass);
|
|
@@ -43239,7 +43580,7 @@ var colors = {
|
|
|
43239
43580
|
};
|
|
43240
43581
|
|
|
43241
43582
|
// src/version.ts
|
|
43242
|
-
var version = "3.
|
|
43583
|
+
var version = "3.156.0";
|
|
43243
43584
|
|
|
43244
43585
|
// src/formatters.ts
|
|
43245
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",
|