circle-ir 3.175.0 → 3.176.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/analysis/arg-type-resolver.d.ts +90 -0
- package/dist/analysis/arg-type-resolver.d.ts.map +1 -0
- package/dist/analysis/arg-type-resolver.js +174 -0
- package/dist/analysis/arg-type-resolver.js.map +1 -0
- package/dist/analysis/passes/sink-filter-pass.d.ts.map +1 -1
- package/dist/analysis/passes/sink-filter-pass.js +38 -0
- package/dist/analysis/passes/sink-filter-pass.js.map +1 -1
- package/dist/analysis/taint-matcher.d.ts.map +1 -1
- package/dist/analysis/taint-matcher.js +42 -5
- package/dist/analysis/taint-matcher.js.map +1 -1
- package/dist/browser/circle-ir.js +109 -5
- package/dist/core/circle-ir-core.cjs +80 -5
- package/dist/core/circle-ir-core.js +80 -5
- package/package.json +1 -1
|
@@ -12602,6 +12602,64 @@ function getDefaultConfig() {
|
|
|
12602
12602
|
};
|
|
12603
12603
|
}
|
|
12604
12604
|
|
|
12605
|
+
// src/analysis/arg-type-resolver.ts
|
|
12606
|
+
function findEnclosingType(callInMethod, types) {
|
|
12607
|
+
if (!callInMethod) return null;
|
|
12608
|
+
for (const t of types) {
|
|
12609
|
+
for (const m of t.methods) {
|
|
12610
|
+
if (m.name === callInMethod) return t;
|
|
12611
|
+
}
|
|
12612
|
+
}
|
|
12613
|
+
return null;
|
|
12614
|
+
}
|
|
12615
|
+
function resolveIdentifierType(name2, callInMethod, types) {
|
|
12616
|
+
if (!name2) return null;
|
|
12617
|
+
const enclosing = findEnclosingType(callInMethod, types);
|
|
12618
|
+
if (enclosing) {
|
|
12619
|
+
for (const m of enclosing.methods) {
|
|
12620
|
+
if (m.name !== callInMethod) continue;
|
|
12621
|
+
for (const p of m.parameters) {
|
|
12622
|
+
if (p.name === name2 && p.type) return p.type;
|
|
12623
|
+
}
|
|
12624
|
+
}
|
|
12625
|
+
for (const f of enclosing.fields) {
|
|
12626
|
+
if (f.name === name2 && f.type) return f.type;
|
|
12627
|
+
}
|
|
12628
|
+
return null;
|
|
12629
|
+
}
|
|
12630
|
+
for (const t of types) {
|
|
12631
|
+
for (const m of t.methods) {
|
|
12632
|
+
for (const p of m.parameters) {
|
|
12633
|
+
if (p.name === name2 && p.type) return p.type;
|
|
12634
|
+
}
|
|
12635
|
+
}
|
|
12636
|
+
for (const f of t.fields) {
|
|
12637
|
+
if (f.name === name2 && f.type) return f.type;
|
|
12638
|
+
}
|
|
12639
|
+
}
|
|
12640
|
+
return null;
|
|
12641
|
+
}
|
|
12642
|
+
function resolveCallReturnType(calleeName, callInMethod, types) {
|
|
12643
|
+
if (!calleeName) return null;
|
|
12644
|
+
const enclosing = findEnclosingType(callInMethod, types);
|
|
12645
|
+
if (enclosing) {
|
|
12646
|
+
for (const m of enclosing.methods) {
|
|
12647
|
+
if (m.name === calleeName && m.return_type) return m.return_type;
|
|
12648
|
+
}
|
|
12649
|
+
}
|
|
12650
|
+
for (const t of types) {
|
|
12651
|
+
for (const m of t.methods) {
|
|
12652
|
+
if (m.name === calleeName && m.return_type) return m.return_type;
|
|
12653
|
+
}
|
|
12654
|
+
}
|
|
12655
|
+
return null;
|
|
12656
|
+
}
|
|
12657
|
+
function isBoundedClassType(rawType) {
|
|
12658
|
+
if (!rawType) return false;
|
|
12659
|
+
const stripped = rawType.trim().replace(/^(?:java\.lang\.)+/, "");
|
|
12660
|
+
return /^Class(?:\s*<[\s\S]*>)?$/.test(stripped);
|
|
12661
|
+
}
|
|
12662
|
+
|
|
12605
12663
|
// src/analysis/taint-matcher.ts
|
|
12606
12664
|
var PYTHON_TAINTED_PATTERNS = [
|
|
12607
12665
|
{ pattern: /\brequest\.args\b/, sourceType: "http_param" },
|
|
@@ -12627,7 +12685,7 @@ function analyzeTaint(calls, types, config = getDefaultConfig(), typeHierarchy,
|
|
|
12627
12685
|
const sources = findSources(calls, types, config.sources, sourceLines, language);
|
|
12628
12686
|
let sinkPatterns = expandPromisifyAliases(config.sinks, sourceLines, language);
|
|
12629
12687
|
sinkPatterns = expandIndirectEvalAliases(sinkPatterns, sourceLines, language);
|
|
12630
|
-
const sinks = findSinks(calls, sinkPatterns, typeHierarchy, language, sourceLines);
|
|
12688
|
+
const sinks = findSinks(calls, sinkPatterns, typeHierarchy, language, sourceLines, types);
|
|
12631
12689
|
const sanitizers = findSanitizers(calls, types, config.sanitizers, sourceLines);
|
|
12632
12690
|
return { sources, sinks, sanitizers };
|
|
12633
12691
|
}
|
|
@@ -13205,13 +13263,30 @@ function isSafeRustCommandCall(call, pattern, language) {
|
|
|
13205
13263
|
return false;
|
|
13206
13264
|
}
|
|
13207
13265
|
var CLASS_LITERAL_RE = /^(?:[A-Za-z_][\w]*\.)*[A-Z][\w]*(?:\[\])*\.class$/;
|
|
13208
|
-
function argIsClassLiteral(call, position) {
|
|
13266
|
+
function argIsClassLiteral(call, position, types) {
|
|
13209
13267
|
const arg = call.arguments.find((a) => a.position === position);
|
|
13210
13268
|
if (!arg) return false;
|
|
13211
13269
|
const expr = (arg.literal ?? arg.expression ?? "").trim();
|
|
13212
13270
|
if (!expr) return false;
|
|
13213
13271
|
if (CLASS_LITERAL_RE.test(expr)) return true;
|
|
13214
|
-
|
|
13272
|
+
if (TYPE_TOKEN_RE.test(expr)) return true;
|
|
13273
|
+
if (!types || types.length === 0) return false;
|
|
13274
|
+
const argExpr = (arg.expression ?? "").trim();
|
|
13275
|
+
const varName = arg.variable ?? "";
|
|
13276
|
+
const isBareIdentifier = varName !== "" && argExpr === varName && !/[(.]/.test(argExpr);
|
|
13277
|
+
if (isBareIdentifier) {
|
|
13278
|
+
const t = resolveIdentifierType(varName, call.in_method, types);
|
|
13279
|
+
if (isBoundedClassType(t)) return true;
|
|
13280
|
+
}
|
|
13281
|
+
const isCallExpr = varName !== "" && new RegExp(`^${escapeRe(varName)}\\s*\\(`).test(argExpr);
|
|
13282
|
+
if (isCallExpr) {
|
|
13283
|
+
const t = resolveCallReturnType(varName, call.in_method, types);
|
|
13284
|
+
if (isBoundedClassType(t)) return true;
|
|
13285
|
+
}
|
|
13286
|
+
return false;
|
|
13287
|
+
}
|
|
13288
|
+
function escapeRe(s) {
|
|
13289
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13215
13290
|
}
|
|
13216
13291
|
var TYPE_TOKEN_RE = /^new\s+(?:TypeReference|TypeToken)\s*<[\s\S]*>\s*\(\s*\)\s*\{\s*\}$/;
|
|
13217
13292
|
function argIsStringLiteral(call, position) {
|
|
@@ -13372,7 +13447,7 @@ function isSafeJinjaRenderCall(call, pattern, language, sourceLines) {
|
|
|
13372
13447
|
}
|
|
13373
13448
|
return false;
|
|
13374
13449
|
}
|
|
13375
|
-
function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
|
|
13450
|
+
function findSinks(calls, patterns, typeHierarchy, language, sourceLines, types) {
|
|
13376
13451
|
const sinkMap = /* @__PURE__ */ new Map();
|
|
13377
13452
|
for (const call of calls) {
|
|
13378
13453
|
for (const pattern of patterns) {
|
|
@@ -13392,7 +13467,7 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
|
|
|
13392
13467
|
if (isSafeJSChildProcessCall(call, pattern, language)) {
|
|
13393
13468
|
continue;
|
|
13394
13469
|
}
|
|
13395
|
-
if (pattern.safe_if_class_literal_at !== void 0 && argIsClassLiteral(call, pattern.safe_if_class_literal_at)) {
|
|
13470
|
+
if (pattern.safe_if_class_literal_at !== void 0 && argIsClassLiteral(call, pattern.safe_if_class_literal_at, types)) {
|
|
13396
13471
|
continue;
|
|
13397
13472
|
}
|
|
13398
13473
|
if (pattern.safe_if_string_literal_at !== void 0 && argIsStringLiteral(call, pattern.safe_if_string_literal_at)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "circle-ir",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.176.0",
|
|
4
4
|
"description": "High-performance Static Application Security Testing (SAST) library for detecting security vulnerabilities through taint analysis",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|