circle-ir 3.57.0 → 3.58.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/configs/sinks/golang.json +61 -0
- package/configs/sinks/nodejs.json +11 -6
- package/configs/sinks/python.json +24 -0
- package/configs/sinks/rust.json +30 -0
- package/configs/sinks/sql.yaml +53 -0
- package/dist/analysis/config-loader.d.ts.map +1 -1
- package/dist/analysis/config-loader.js +57 -9
- package/dist/analysis/config-loader.js.map +1 -1
- package/dist/analysis/constant-propagation/patterns.d.ts.map +1 -1
- package/dist/analysis/constant-propagation/patterns.js +12 -0
- package/dist/analysis/constant-propagation/patterns.js.map +1 -1
- package/dist/analysis/constant-propagation/propagator.d.ts +62 -0
- package/dist/analysis/constant-propagation/propagator.d.ts.map +1 -1
- package/dist/analysis/constant-propagation/propagator.js +275 -7
- package/dist/analysis/constant-propagation/propagator.js.map +1 -1
- package/dist/analysis/passes/language-sources-pass.d.ts.map +1 -1
- package/dist/analysis/passes/language-sources-pass.js +55 -14
- package/dist/analysis/passes/language-sources-pass.js.map +1 -1
- package/dist/analysis/passes/security-headers-pass.d.ts.map +1 -1
- package/dist/analysis/passes/security-headers-pass.js +93 -0
- package/dist/analysis/passes/security-headers-pass.js.map +1 -1
- package/dist/analysis/passes/sink-filter-pass.d.ts.map +1 -1
- package/dist/analysis/passes/sink-filter-pass.js +16 -1
- package/dist/analysis/passes/sink-filter-pass.js.map +1 -1
- package/dist/analysis/passes/taint-propagation-pass.d.ts.map +1 -1
- package/dist/analysis/passes/taint-propagation-pass.js +153 -9
- package/dist/analysis/passes/taint-propagation-pass.js.map +1 -1
- package/dist/analysis/taint-matcher.d.ts.map +1 -1
- package/dist/analysis/taint-matcher.js +116 -2
- package/dist/analysis/taint-matcher.js.map +1 -1
- package/dist/analysis/taint-propagation.d.ts.map +1 -1
- package/dist/analysis/taint-propagation.js +25 -1
- package/dist/analysis/taint-propagation.js.map +1 -1
- package/dist/browser/circle-ir.js +500 -45
- package/dist/core/circle-ir-core.cjs +368 -21
- package/dist/core/circle-ir-core.js +368 -21
- package/dist/types/config.d.ts +7 -0
- package/dist/types/config.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -10179,11 +10179,14 @@ var DEFAULT_SOURCES = [
|
|
|
10179
10179
|
// Rocket
|
|
10180
10180
|
{ method: "param", class: "Request", type: "http_param", severity: "high", return_tainted: true },
|
|
10181
10181
|
{ method: "cookies", class: "Request", type: "http_cookie", severity: "high", return_tainted: true },
|
|
10182
|
-
// Axum extractors
|
|
10183
|
-
|
|
10184
|
-
|
|
10185
|
-
|
|
10186
|
-
{ method: "
|
|
10182
|
+
// Axum extractors — Rust-only. The simple names `Json`/`Query`/`Path`/`Form`
|
|
10183
|
+
// collide with stdlib types in other ecosystems (notably Python's
|
|
10184
|
+
// `pathlib.Path` constructor and `flask.Form`), so they MUST be
|
|
10185
|
+
// language-scoped to Rust to avoid spurious source matches.
|
|
10186
|
+
{ method: "Json", type: "http_body", severity: "high", return_tainted: true, languages: ["rust"] },
|
|
10187
|
+
{ method: "Query", type: "http_param", severity: "high", return_tainted: true, languages: ["rust"] },
|
|
10188
|
+
{ method: "Path", type: "http_path", severity: "high", return_tainted: true, languages: ["rust"] },
|
|
10189
|
+
{ method: "Form", type: "http_param", severity: "high", return_tainted: true, languages: ["rust"] },
|
|
10187
10190
|
// Rust std library
|
|
10188
10191
|
{ method: "var", class: "env", type: "env_input", severity: "medium", return_tainted: true },
|
|
10189
10192
|
{ method: "var_os", class: "env", type: "env_input", severity: "medium", return_tainted: true },
|
|
@@ -10386,10 +10389,15 @@ var DEFAULT_SINKS = [
|
|
|
10386
10389
|
{ method: "PathResource", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10387
10390
|
// Additional resource/file patterns
|
|
10388
10391
|
{ method: "forFile", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10389
|
-
|
|
10390
|
-
|
|
10391
|
-
|
|
10392
|
-
|
|
10392
|
+
// Java NIO `Path.resolve(other)` — joining with an untrusted `other` can
|
|
10393
|
+
// escape the parent directory. Language-scoped to Java because the simple
|
|
10394
|
+
// name `resolve` collides with Python `pathlib.Path.resolve()`
|
|
10395
|
+
// (a canonicalization SANITIZER, no argument), JS `Promise.resolve(...)`,
|
|
10396
|
+
// and Rust `Path::canonicalize` variants. Sprint 9 #48.2.
|
|
10397
|
+
{ method: "resolve", class: "Path", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["java"] },
|
|
10398
|
+
{ method: "resolve", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["java"] },
|
|
10399
|
+
{ method: "resolveSibling", class: "Path", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["java"] },
|
|
10400
|
+
{ method: "relativize", class: "Path", type: "path_traversal", cwe: "CWE-22", severity: "medium", arg_positions: [0], languages: ["java"] },
|
|
10393
10401
|
// Static file configuration
|
|
10394
10402
|
{ method: "staticFiles", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10395
10403
|
{ method: "setRoot", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
@@ -11546,6 +11554,16 @@ var DEFAULT_SANITIZERS = [
|
|
|
11546
11554
|
// Returns just filename, strips path
|
|
11547
11555
|
{ method: "canonicalize", removes: ["path_traversal"] },
|
|
11548
11556
|
// Resolves symlinks and normalizes
|
|
11557
|
+
// Go path sanitizers (#51) — filepath.Base strips directory components
|
|
11558
|
+
// (fully sanitizes), filepath.Clean / path.Clean normalize away ../ segments
|
|
11559
|
+
// (defense-in-depth — mirrors Java getCanonicalPath in this table; the
|
|
11560
|
+
// stricter Clean+HasPrefix guard recognition is tracked separately).
|
|
11561
|
+
// EvalSymlinks is the Go equivalent of Java's Path.toRealPath.
|
|
11562
|
+
{ method: "Base", class: "filepath", removes: ["path_traversal"] },
|
|
11563
|
+
{ method: "Base", class: "path", removes: ["path_traversal"] },
|
|
11564
|
+
{ method: "Clean", class: "filepath", removes: ["path_traversal"] },
|
|
11565
|
+
{ method: "Clean", class: "path", removes: ["path_traversal"] },
|
|
11566
|
+
{ method: "EvalSymlinks", class: "filepath", removes: ["path_traversal"] },
|
|
11549
11567
|
// Log Injection sanitizers
|
|
11550
11568
|
{ method: "replace", removes: ["log_injection"] },
|
|
11551
11569
|
// Used to remove newlines/control chars
|
|
@@ -11640,6 +11658,8 @@ var DEFAULT_SANITIZERS = [
|
|
|
11640
11658
|
{ method: "abspath", class: "os.path", removes: ["path_traversal"] },
|
|
11641
11659
|
{ method: "realpath", class: "path", removes: ["path_traversal"] },
|
|
11642
11660
|
{ method: "abspath", class: "path", removes: ["path_traversal"] },
|
|
11661
|
+
// pathlib.Path.resolve() — canonicalizes path, resolves symlinks (Python 3)
|
|
11662
|
+
{ method: "resolve", class: "Path", removes: ["path_traversal"] },
|
|
11643
11663
|
// Python Type coercion
|
|
11644
11664
|
{ method: "int", removes: ["sql_injection", "command_injection", "xss"] },
|
|
11645
11665
|
{ method: "float", removes: ["sql_injection", "command_injection"] },
|
|
@@ -11672,8 +11692,36 @@ var DEFAULT_SANITIZERS = [
|
|
|
11672
11692
|
{ method: "encode_attribute", class: "html_escape", removes: ["xss"] },
|
|
11673
11693
|
{ method: "escape_html", removes: ["xss"] },
|
|
11674
11694
|
// Rust Type coercion (parsing)
|
|
11675
|
-
{ method: "parse", removes: ["sql_injection", "command_injection", "xss"] }
|
|
11695
|
+
{ method: "parse", removes: ["sql_injection", "command_injection", "xss"] },
|
|
11676
11696
|
// str.parse::<i32>()
|
|
11697
|
+
// =========================================================================
|
|
11698
|
+
// Type-cast taint barriers (#57)
|
|
11699
|
+
// Numeric/UUID casts cannot carry a string-injection payload.
|
|
11700
|
+
// =========================================================================
|
|
11701
|
+
// Java numeric parse — Integer.parseInt, Long.parseLong, etc.
|
|
11702
|
+
{ method: "parseInt", class: "Integer", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11703
|
+
{ method: "parseLong", class: "Long", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11704
|
+
{ method: "parseFloat", class: "Float", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11705
|
+
{ method: "parseDouble", class: "Double", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11706
|
+
{ method: "parseShort", class: "Short", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11707
|
+
{ method: "parseByte", class: "Byte", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11708
|
+
// Java UUID parse — UUID.fromString rejects non-UUID strings
|
|
11709
|
+
{ method: "fromString", class: "UUID", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11710
|
+
// JavaScript numeric coercion (Number/parseInt/parseFloat already covered above; add path_traversal/code_injection)
|
|
11711
|
+
{ method: "BigInt", removes: ["sql_injection", "nosql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11712
|
+
// Go numeric parse — strconv.Atoi, ParseInt, ParseFloat, ParseUint, ParseBool
|
|
11713
|
+
{ method: "Atoi", class: "strconv", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11714
|
+
{ method: "ParseInt", class: "strconv", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11715
|
+
{ method: "ParseFloat", class: "strconv", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11716
|
+
{ method: "ParseUint", class: "strconv", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11717
|
+
{ method: "ParseBool", class: "strconv", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11718
|
+
// Go UUID parse
|
|
11719
|
+
{ method: "Parse", class: "uuid", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11720
|
+
{ method: "MustParse", class: "uuid", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11721
|
+
// Python — int/float already covered above; add bool + UUID/Decimal casts
|
|
11722
|
+
{ method: "bool", removes: ["sql_injection", "command_injection", "xss", "code_injection"] },
|
|
11723
|
+
{ method: "UUID", class: "uuid", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] },
|
|
11724
|
+
{ method: "Decimal", class: "decimal", removes: ["sql_injection", "command_injection", "path_traversal", "code_injection"] }
|
|
11677
11725
|
];
|
|
11678
11726
|
function getDefaultConfig() {
|
|
11679
11727
|
return {
|
|
@@ -11703,7 +11751,7 @@ function analyzeTaint(calls, types, config = getDefaultConfig(), typeHierarchy,
|
|
|
11703
11751
|
const sourceLines = code !== void 0 ? code.split("\n") : void 0;
|
|
11704
11752
|
const sources = findSources(calls, types, config.sources, sourceLines, language);
|
|
11705
11753
|
const sinks = findSinks(calls, config.sinks, typeHierarchy, language, sourceLines);
|
|
11706
|
-
const sanitizers = findSanitizers(calls, types, config.sanitizers);
|
|
11754
|
+
const sanitizers = findSanitizers(calls, types, config.sanitizers, sourceLines);
|
|
11707
11755
|
return { sources, sinks, sanitizers };
|
|
11708
11756
|
}
|
|
11709
11757
|
function attachSourceLineCode(sources, sinks, code) {
|
|
@@ -11723,6 +11771,9 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
11723
11771
|
const sources = [];
|
|
11724
11772
|
for (const call of calls) {
|
|
11725
11773
|
for (const pattern of patterns) {
|
|
11774
|
+
if (pattern.languages && pattern.languages.length > 0 && language !== void 0 && !pattern.languages.includes(language)) {
|
|
11775
|
+
continue;
|
|
11776
|
+
}
|
|
11726
11777
|
if (matchesSourcePattern(call, pattern)) {
|
|
11727
11778
|
sources.push({
|
|
11728
11779
|
type: pattern.type,
|
|
@@ -12359,6 +12410,15 @@ function receiverMightBeClass(receiver, className) {
|
|
|
12359
12410
|
if (receiver === className) {
|
|
12360
12411
|
return true;
|
|
12361
12412
|
}
|
|
12413
|
+
if (receiver.endsWith(")")) {
|
|
12414
|
+
const ctorMatch = receiver.match(/^(\w+)\(/);
|
|
12415
|
+
if (ctorMatch) {
|
|
12416
|
+
const ctorName = ctorMatch[1];
|
|
12417
|
+
if (ctorName === className || ctorName.toLowerCase() === className.toLowerCase()) {
|
|
12418
|
+
return true;
|
|
12419
|
+
}
|
|
12420
|
+
}
|
|
12421
|
+
}
|
|
12362
12422
|
if (receiver.includes("::")) {
|
|
12363
12423
|
const scopePrefix = receiver.match(/^(\w+)::/);
|
|
12364
12424
|
if (scopePrefix) {
|
|
@@ -12626,7 +12686,7 @@ function calculateSinkConfidence(call, pattern) {
|
|
|
12626
12686
|
}
|
|
12627
12687
|
return Math.min(confidence, 1);
|
|
12628
12688
|
}
|
|
12629
|
-
function findSanitizers(calls, types, patterns) {
|
|
12689
|
+
function findSanitizers(calls, types, patterns, sourceLines) {
|
|
12630
12690
|
const sanitizers = [];
|
|
12631
12691
|
const sanitizerMethods = /* @__PURE__ */ new Set();
|
|
12632
12692
|
for (const type of types) {
|
|
@@ -12636,6 +12696,66 @@ function findSanitizers(calls, types, patterns) {
|
|
|
12636
12696
|
}
|
|
12637
12697
|
}
|
|
12638
12698
|
}
|
|
12699
|
+
const wrapperSanitizers = /* @__PURE__ */ new Map();
|
|
12700
|
+
for (const type of types) {
|
|
12701
|
+
for (const method of type.methods) {
|
|
12702
|
+
const bodySize = method.end_line - method.start_line;
|
|
12703
|
+
if (bodySize < 0 || bodySize > 2) continue;
|
|
12704
|
+
const paramNames = new Set(method.parameters.map((p) => p.name));
|
|
12705
|
+
if (paramNames.size === 0) continue;
|
|
12706
|
+
const inside = [];
|
|
12707
|
+
for (const c of calls) {
|
|
12708
|
+
if (c.location.line < method.start_line || c.location.line > method.end_line) continue;
|
|
12709
|
+
if (c.method_name === method.name) continue;
|
|
12710
|
+
inside.push(c);
|
|
12711
|
+
}
|
|
12712
|
+
if (inside.length !== 1) continue;
|
|
12713
|
+
const innerCall = inside[0];
|
|
12714
|
+
let matched;
|
|
12715
|
+
for (const pattern of patterns) {
|
|
12716
|
+
if (matchesSanitizerPattern(innerCall, pattern)) {
|
|
12717
|
+
matched = pattern;
|
|
12718
|
+
break;
|
|
12719
|
+
}
|
|
12720
|
+
}
|
|
12721
|
+
if (!matched || !matched.removes || matched.removes.length === 0) continue;
|
|
12722
|
+
let argOk = false;
|
|
12723
|
+
for (const arg of innerCall.arguments) {
|
|
12724
|
+
if (arg.variable && paramNames.has(arg.variable)) {
|
|
12725
|
+
argOk = true;
|
|
12726
|
+
break;
|
|
12727
|
+
}
|
|
12728
|
+
}
|
|
12729
|
+
if (!argOk) continue;
|
|
12730
|
+
if (sourceLines) {
|
|
12731
|
+
const lineText = sourceLines[innerCall.location.line - 1] ?? "";
|
|
12732
|
+
const stripped = lineText.trim();
|
|
12733
|
+
const returnMatch = stripped.match(/^return\s+(?:await\s+)?(.*)$/);
|
|
12734
|
+
if (!returnMatch) continue;
|
|
12735
|
+
const after = returnMatch[1].replace(/;\s*$/, "").trimEnd();
|
|
12736
|
+
const callPrefix = innerCall.receiver ? `${innerCall.receiver}.${innerCall.method_name}(` : `${innerCall.method_name}(`;
|
|
12737
|
+
if (!after.startsWith(callPrefix)) continue;
|
|
12738
|
+
if (!after.endsWith(")")) continue;
|
|
12739
|
+
}
|
|
12740
|
+
const existing = wrapperSanitizers.get(method.name);
|
|
12741
|
+
if (existing) {
|
|
12742
|
+
const set = /* @__PURE__ */ new Set([...existing, ...matched.removes]);
|
|
12743
|
+
wrapperSanitizers.set(method.name, Array.from(set));
|
|
12744
|
+
} else {
|
|
12745
|
+
wrapperSanitizers.set(method.name, [...matched.removes]);
|
|
12746
|
+
}
|
|
12747
|
+
}
|
|
12748
|
+
}
|
|
12749
|
+
for (const call of calls) {
|
|
12750
|
+
const removes = wrapperSanitizers.get(call.method_name);
|
|
12751
|
+
if (!removes) continue;
|
|
12752
|
+
sanitizers.push({
|
|
12753
|
+
type: "derived_wrapper",
|
|
12754
|
+
method: formatSanitizerMethod(call),
|
|
12755
|
+
line: call.location.line,
|
|
12756
|
+
sanitizes: removes
|
|
12757
|
+
});
|
|
12758
|
+
}
|
|
12639
12759
|
for (const call of calls) {
|
|
12640
12760
|
if (sanitizerMethods.has(call.method_name)) {
|
|
12641
12761
|
sanitizers.push({
|
|
@@ -12958,6 +13078,15 @@ var CodeGraph = class {
|
|
|
12958
13078
|
};
|
|
12959
13079
|
|
|
12960
13080
|
// src/analysis/taint-propagation.ts
|
|
13081
|
+
function buildSanitizersByLine(sanitizers) {
|
|
13082
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
13083
|
+
for (const san of sanitizers) {
|
|
13084
|
+
const existing = out2.get(san.line);
|
|
13085
|
+
if (existing) existing.push(san);
|
|
13086
|
+
else out2.set(san.line, [san]);
|
|
13087
|
+
}
|
|
13088
|
+
return out2;
|
|
13089
|
+
}
|
|
12961
13090
|
function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanitizers, sanitizersArg) {
|
|
12962
13091
|
let graph;
|
|
12963
13092
|
let sources;
|
|
@@ -12993,7 +13122,7 @@ function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanit
|
|
|
12993
13122
|
const defsByLine = graph.defsByLine;
|
|
12994
13123
|
const usesByLine = graph.usesByLine;
|
|
12995
13124
|
const callsByLine = graph.callsByLine;
|
|
12996
|
-
const sanitizersByLine = graph.sanitizersByLine;
|
|
13125
|
+
const sanitizersByLine = sanitizers.length > 0 ? buildSanitizersByLine(sanitizers) : graph.sanitizersByLine;
|
|
12997
13126
|
const defById = graph.defById;
|
|
12998
13127
|
const rawInitialTaint = findInitialTaint(sources, callsByLine, defsByLine);
|
|
12999
13128
|
const initialTaint = rawInitialTaint.filter((tv) => {
|
|
@@ -13666,7 +13795,32 @@ var SANITIZER_METHODS = /* @__PURE__ */ new Set([
|
|
|
13666
13795
|
"validatePath",
|
|
13667
13796
|
"validateCityName",
|
|
13668
13797
|
"validateInput",
|
|
13669
|
-
"sanitizeInput"
|
|
13798
|
+
"sanitizeInput",
|
|
13799
|
+
// Type-cast barriers (#57) — numeric/boolean casts cannot carry a string
|
|
13800
|
+
// injection payload. Conservative whitelist; ambiguous names like `valueOf`,
|
|
13801
|
+
// `Parse`, `fromString` are intentionally excluded.
|
|
13802
|
+
// Java
|
|
13803
|
+
"parseInt",
|
|
13804
|
+
"parseLong",
|
|
13805
|
+
"parseFloat",
|
|
13806
|
+
"parseDouble",
|
|
13807
|
+
"parseShort",
|
|
13808
|
+
"parseByte",
|
|
13809
|
+
"fromString",
|
|
13810
|
+
// UUID.fromString — parses strict UUID format, rejects injection
|
|
13811
|
+
// JS/TS (parseInt/parseFloat covered above)
|
|
13812
|
+
"Number",
|
|
13813
|
+
"BigInt",
|
|
13814
|
+
// Go
|
|
13815
|
+
"Atoi",
|
|
13816
|
+
"ParseInt",
|
|
13817
|
+
"ParseFloat",
|
|
13818
|
+
"ParseUint",
|
|
13819
|
+
"ParseBool",
|
|
13820
|
+
// Python
|
|
13821
|
+
"int",
|
|
13822
|
+
"float",
|
|
13823
|
+
"bool"
|
|
13670
13824
|
]);
|
|
13671
13825
|
var ANTI_SANITIZER_METHODS = /* @__PURE__ */ new Set([
|
|
13672
13826
|
// URL decoding (reverses URL encoding)
|
|
@@ -13796,6 +13950,10 @@ var ConstantPropagator = class _ConstantPropagator {
|
|
|
13796
13950
|
inConstructor = false;
|
|
13797
13951
|
// Map constructor parameter names to their positions (0-indexed)
|
|
13798
13952
|
constructorParamPositions = /* @__PURE__ */ new Map();
|
|
13953
|
+
// Sprint 9 #58.1 — names of `static final Pattern` fields whose compiled
|
|
13954
|
+
// regex is strict-anchored (provably matches a bounded character set).
|
|
13955
|
+
// Populated lazily on first access via `getSafePatternFields()`.
|
|
13956
|
+
safePatternFieldsCache = null;
|
|
13799
13957
|
/**
|
|
13800
13958
|
* Analyze source code and build constant propagation state.
|
|
13801
13959
|
*/
|
|
@@ -13829,6 +13987,7 @@ var ConstantPropagator = class _ConstantPropagator {
|
|
|
13829
13987
|
this.currentClassName = null;
|
|
13830
13988
|
this.inConstructor = false;
|
|
13831
13989
|
this.constructorParamPositions.clear();
|
|
13990
|
+
this.safePatternFieldsCache = null;
|
|
13832
13991
|
this.collectClassFields(tree.rootNode);
|
|
13833
13992
|
for (const methodName of sanitizerMethods) {
|
|
13834
13993
|
this.methodReturnsSanitized.add(methodName);
|
|
@@ -13838,6 +13997,7 @@ var ConstantPropagator = class _ConstantPropagator {
|
|
|
13838
13997
|
(name2) => this.lookupSymbol(name2)
|
|
13839
13998
|
);
|
|
13840
13999
|
this.analyzeMethodReturns(tree.rootNode);
|
|
14000
|
+
this.seedPythonModuleConstants(tree.rootNode);
|
|
13841
14001
|
this.visit(tree.rootNode);
|
|
13842
14002
|
this.refineTaintFromConstants();
|
|
13843
14003
|
const resultTainted = new Set(this.tainted);
|
|
@@ -14198,6 +14358,162 @@ var ConstantPropagator = class _ConstantPropagator {
|
|
|
14198
14358
|
}
|
|
14199
14359
|
}
|
|
14200
14360
|
}
|
|
14361
|
+
/**
|
|
14362
|
+
* Sprint 9 #55 — seed the symbol table with Python module-level constant
|
|
14363
|
+
* assignments. Walks only direct children of the `module` root and adds
|
|
14364
|
+
* `IDENT = <primitive literal>` to `symbols` so `if IDENT:` guards inside
|
|
14365
|
+
* downstream functions can be folded to dead code.
|
|
14366
|
+
*
|
|
14367
|
+
* Recognized literal RHS kinds: `true`/`false` (booleans), integer/float
|
|
14368
|
+
* literals, string literals. The ExpressionEvaluator already understands
|
|
14369
|
+
* each via the same lookup callback; we just need the symbol present.
|
|
14370
|
+
*/
|
|
14371
|
+
/**
|
|
14372
|
+
* Sprint 9 #55 — gate `field_declaration` folding to primitive literals.
|
|
14373
|
+
*
|
|
14374
|
+
* The deep-nesting regression (cognium-ai#88) constructs a Java
|
|
14375
|
+
* `static final String hyphenData = "a" + "b" + ... (10k segments)` at the
|
|
14376
|
+
* class level. `handleVariableDeclaration` would otherwise dispatch
|
|
14377
|
+
* `evaluateExpression` on the deeply nested binary AST and blow the V8
|
|
14378
|
+
* stack. The dead-code-by-const-guard pattern (`if (DEBUG)`) only requires
|
|
14379
|
+
* `boolean`/`integer`/`string` (single-literal) RHS folding, so restrict
|
|
14380
|
+
* to those node types.
|
|
14381
|
+
*/
|
|
14382
|
+
fieldDeclHasPrimitiveLiteralValue(node) {
|
|
14383
|
+
const primitive = /* @__PURE__ */ new Set([
|
|
14384
|
+
// Java literal node types
|
|
14385
|
+
"true",
|
|
14386
|
+
"false",
|
|
14387
|
+
"null_literal",
|
|
14388
|
+
"decimal_integer_literal",
|
|
14389
|
+
"hex_integer_literal",
|
|
14390
|
+
"octal_integer_literal",
|
|
14391
|
+
"binary_integer_literal",
|
|
14392
|
+
"decimal_floating_point_literal",
|
|
14393
|
+
"hex_floating_point_literal",
|
|
14394
|
+
"character_literal",
|
|
14395
|
+
"string_literal",
|
|
14396
|
+
// JS/TS literal node types (defensive, in case other langs reuse it)
|
|
14397
|
+
"number",
|
|
14398
|
+
"string"
|
|
14399
|
+
]);
|
|
14400
|
+
for (const child of node.children) {
|
|
14401
|
+
if (child.type !== "variable_declarator") continue;
|
|
14402
|
+
const value = child.childForFieldName("value");
|
|
14403
|
+
if (!value) continue;
|
|
14404
|
+
if (!primitive.has(value.type)) return false;
|
|
14405
|
+
}
|
|
14406
|
+
return true;
|
|
14407
|
+
}
|
|
14408
|
+
/**
|
|
14409
|
+
* Sprint 9 #58.1 — collect the set of class-level `Pattern` field names
|
|
14410
|
+
* whose compiled regex is strict-anchored, i.e. provably matches a
|
|
14411
|
+
* bounded character set with no wildcard escape. A subsequent
|
|
14412
|
+
* `if (!FIELD.matcher(var).matches()) throw ...;` guard then proves
|
|
14413
|
+
* `var` is sanitized after the if.
|
|
14414
|
+
*
|
|
14415
|
+
* Recognized initializer shapes (scanned via source-text regex to avoid
|
|
14416
|
+
* threading another AST walk):
|
|
14417
|
+
* `static final Pattern FIELD = Pattern.compile("regex");`
|
|
14418
|
+
*
|
|
14419
|
+
* Strict-anchored regex criteria:
|
|
14420
|
+
* - starts with `^` and ends with `$`
|
|
14421
|
+
* - after stripping `[...]` character classes, must not contain `.` or
|
|
14422
|
+
* `|` (a `.` could match anything; `|` admits an arbitrary alternative)
|
|
14423
|
+
*/
|
|
14424
|
+
getSafePatternFields() {
|
|
14425
|
+
if (this.safePatternFieldsCache !== null) return this.safePatternFieldsCache;
|
|
14426
|
+
const set = /* @__PURE__ */ new Set();
|
|
14427
|
+
const re = /\b(?:public\s+|private\s+|protected\s+)?(?:static\s+final|final\s+static)\s+(?:java\.util\.regex\.)?Pattern\s+(\w+)\s*=\s*(?:java\.util\.regex\.)?Pattern\s*\.\s*compile\s*\(\s*"((?:[^"\\]|\\.)*)"/g;
|
|
14428
|
+
let m;
|
|
14429
|
+
while ((m = re.exec(this.source)) !== null) {
|
|
14430
|
+
const name2 = m[1];
|
|
14431
|
+
const regex = m[2];
|
|
14432
|
+
if (this.isStrictAnchoredRegex(regex)) set.add(name2);
|
|
14433
|
+
}
|
|
14434
|
+
this.safePatternFieldsCache = set;
|
|
14435
|
+
return set;
|
|
14436
|
+
}
|
|
14437
|
+
isStrictAnchoredRegex(re) {
|
|
14438
|
+
if (!re.startsWith("^") || !re.endsWith("$")) return false;
|
|
14439
|
+
const stripped = re.replace(/\[(?:[^\]\\]|\\.)*\]/g, "");
|
|
14440
|
+
const cleaned = stripped.replace(/\\./g, "");
|
|
14441
|
+
if (cleaned.includes(".")) return false;
|
|
14442
|
+
if (cleaned.includes("|")) return false;
|
|
14443
|
+
return true;
|
|
14444
|
+
}
|
|
14445
|
+
/**
|
|
14446
|
+
* Sprint 9 #58.1 — detect the regex-allowlist guard pattern.
|
|
14447
|
+
*
|
|
14448
|
+
* if (!SAFE_NAME.matcher(var).matches()) { throw ...; }
|
|
14449
|
+
*
|
|
14450
|
+
* Returns the guarded variable name if the pattern matches AND
|
|
14451
|
+
* `SAFE_NAME` is a recognized strict-anchored Pattern field, otherwise
|
|
14452
|
+
* null. Caller drops the variable from `tainted` after the if-block.
|
|
14453
|
+
*/
|
|
14454
|
+
detectRegexAllowlistGuard(condition, consequence) {
|
|
14455
|
+
if (!consequence) return null;
|
|
14456
|
+
let condText = getNodeText2(condition, this.source).replace(/\s+/g, "");
|
|
14457
|
+
while (condText.startsWith("(") && condText.endsWith(")")) {
|
|
14458
|
+
const inner = condText.slice(1, -1);
|
|
14459
|
+
let depth = 0;
|
|
14460
|
+
let balanced = true;
|
|
14461
|
+
for (let i2 = 0; i2 < inner.length; i2++) {
|
|
14462
|
+
if (inner[i2] === "(") depth++;
|
|
14463
|
+
else if (inner[i2] === ")") depth--;
|
|
14464
|
+
if (depth < 0) {
|
|
14465
|
+
balanced = false;
|
|
14466
|
+
break;
|
|
14467
|
+
}
|
|
14468
|
+
}
|
|
14469
|
+
if (!balanced || depth !== 0) break;
|
|
14470
|
+
condText = inner;
|
|
14471
|
+
}
|
|
14472
|
+
const m = condText.match(/^!(\w+)\.matcher\((\w+)\)\.matches\(\)$/);
|
|
14473
|
+
if (!m) return null;
|
|
14474
|
+
const patternName = m[1];
|
|
14475
|
+
const varName = m[2];
|
|
14476
|
+
if (!this.getSafePatternFields().has(patternName)) return null;
|
|
14477
|
+
if (!this.consequenceContainsThrow(consequence)) return null;
|
|
14478
|
+
return varName;
|
|
14479
|
+
}
|
|
14480
|
+
consequenceContainsThrow(node) {
|
|
14481
|
+
if (node.type === "throw_statement") return true;
|
|
14482
|
+
const stack = [node];
|
|
14483
|
+
while (stack.length > 0) {
|
|
14484
|
+
const n = stack.pop();
|
|
14485
|
+
if (!n) continue;
|
|
14486
|
+
if (n.type === "throw_statement") return true;
|
|
14487
|
+
if (n.type === "if_statement" || n.type === "switch_statement") continue;
|
|
14488
|
+
for (const c of n.children) stack.push(c);
|
|
14489
|
+
}
|
|
14490
|
+
return false;
|
|
14491
|
+
}
|
|
14492
|
+
seedPythonModuleConstants(root) {
|
|
14493
|
+
if (root.type !== "module") return;
|
|
14494
|
+
for (const child of root.children) {
|
|
14495
|
+
const target = child.type === "assignment" ? child : child.type === "expression_statement" && child.children.length > 0 ? child.children[0] : null;
|
|
14496
|
+
if (!target || target.type !== "assignment") continue;
|
|
14497
|
+
const left = target.childForFieldName("left");
|
|
14498
|
+
const right = target.childForFieldName("right");
|
|
14499
|
+
if (!left || !right) continue;
|
|
14500
|
+
if (left.type !== "identifier") continue;
|
|
14501
|
+
const allowed = /* @__PURE__ */ new Set([
|
|
14502
|
+
"true",
|
|
14503
|
+
"false",
|
|
14504
|
+
"none",
|
|
14505
|
+
"integer",
|
|
14506
|
+
"float",
|
|
14507
|
+
"string"
|
|
14508
|
+
]);
|
|
14509
|
+
if (!allowed.has(right.type)) continue;
|
|
14510
|
+
const name2 = getNodeText2(left, this.source);
|
|
14511
|
+
if (!name2) continue;
|
|
14512
|
+
const value = this.evaluateExpression(right);
|
|
14513
|
+
if (!isKnown(value)) continue;
|
|
14514
|
+
this.symbols.set(name2, value);
|
|
14515
|
+
}
|
|
14516
|
+
}
|
|
14201
14517
|
findAllMethods(node) {
|
|
14202
14518
|
const methods = [];
|
|
14203
14519
|
const stack = [node];
|
|
@@ -14292,6 +14608,11 @@ var ConstantPropagator = class _ConstantPropagator {
|
|
|
14292
14608
|
case "local_variable_declaration":
|
|
14293
14609
|
this.handleVariableDeclaration(node);
|
|
14294
14610
|
return false;
|
|
14611
|
+
case "field_declaration":
|
|
14612
|
+
if (this.fieldDeclHasPrimitiveLiteralValue(node)) {
|
|
14613
|
+
this.handleVariableDeclaration(node);
|
|
14614
|
+
}
|
|
14615
|
+
return false;
|
|
14295
14616
|
case "assignment_expression":
|
|
14296
14617
|
this.handleAssignment(node);
|
|
14297
14618
|
return false;
|
|
@@ -14782,6 +15103,16 @@ var ConstantPropagator = class _ConstantPropagator {
|
|
|
14782
15103
|
}
|
|
14783
15104
|
this.inConditionalBranch = wasInConditional;
|
|
14784
15105
|
this.tainted = /* @__PURE__ */ new Set([...taintedBefore, ...taintedAfterThen, ...taintedAfterElse]);
|
|
15106
|
+
const guardedVar = this.detectRegexAllowlistGuard(condition, consequence);
|
|
15107
|
+
if (guardedVar) {
|
|
15108
|
+
this.tainted.delete(guardedVar);
|
|
15109
|
+
this.sanitizedVars.add(guardedVar);
|
|
15110
|
+
const scoped = this.getScopedName(guardedVar);
|
|
15111
|
+
if (scoped !== guardedVar) {
|
|
15112
|
+
this.tainted.delete(scoped);
|
|
15113
|
+
this.sanitizedVars.add(scoped);
|
|
15114
|
+
}
|
|
15115
|
+
}
|
|
14785
15116
|
}
|
|
14786
15117
|
}
|
|
14787
15118
|
/**
|
|
@@ -14972,17 +15303,33 @@ var ConstantPropagator = class _ConstantPropagator {
|
|
|
14972
15303
|
/**
|
|
14973
15304
|
* Check if an expression is a call to a sanitizer method.
|
|
14974
15305
|
* This includes both built-in sanitizers and @sanitizer annotated methods.
|
|
15306
|
+
* Handles Java (`method_invocation`), Go/JS/TS (`call_expression`), and
|
|
15307
|
+
* Python (`call`) AST shapes.
|
|
14975
15308
|
*/
|
|
14976
15309
|
isSanitizerMethodCall(node) {
|
|
14977
|
-
|
|
14978
|
-
|
|
15310
|
+
const methodName = this.extractCallName(node);
|
|
15311
|
+
if (!methodName) return false;
|
|
15312
|
+
return SANITIZER_METHODS.has(methodName) || this.methodReturnsSanitized.has(methodName);
|
|
15313
|
+
}
|
|
15314
|
+
/**
|
|
15315
|
+
* Extract the trailing method/function name from any call node shape:
|
|
15316
|
+
* Java `method_invocation` — name field
|
|
15317
|
+
* Go/JS `call_expression` — function field (identifier or selector/member)
|
|
15318
|
+
* Python `call` — function field (identifier or attribute)
|
|
15319
|
+
*/
|
|
15320
|
+
extractCallName(node) {
|
|
15321
|
+
let fnNode = null;
|
|
15322
|
+
if (node.type === "method_invocation") {
|
|
15323
|
+
fnNode = node.childForFieldName("name");
|
|
15324
|
+
} else if (node.type === "call_expression" || node.type === "call") {
|
|
15325
|
+
fnNode = node.childForFieldName("function");
|
|
14979
15326
|
}
|
|
14980
|
-
|
|
14981
|
-
if (
|
|
14982
|
-
|
|
15327
|
+
if (!fnNode) return null;
|
|
15328
|
+
if (fnNode.type === "selector_expression" || fnNode.type === "member_expression" || fnNode.type === "attribute") {
|
|
15329
|
+
const tail = fnNode.childForFieldName("field") || fnNode.childForFieldName("property") || fnNode.childForFieldName("attribute");
|
|
15330
|
+
if (tail) return getNodeText2(tail, this.source);
|
|
14983
15331
|
}
|
|
14984
|
-
|
|
14985
|
-
return SANITIZER_METHODS.has(methodName) || this.methodReturnsSanitized.has(methodName);
|
|
15332
|
+
return getNodeText2(fnNode, this.source);
|
|
14986
15333
|
}
|
|
14987
15334
|
/**
|
|
14988
15335
|
* Check if an expression is a call to an anti-sanitizer method.
|
package/dist/types/config.d.ts
CHANGED
|
@@ -17,6 +17,13 @@ export interface SourcePattern {
|
|
|
17
17
|
return_tainted?: boolean;
|
|
18
18
|
param_tainted?: boolean;
|
|
19
19
|
property_tainted?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Restrict the pattern to specific source languages. When omitted, the
|
|
22
|
+
* pattern matches regardless of language. Use this for sources whose
|
|
23
|
+
* method name collides across language ecosystems (e.g. Rust Axum's
|
|
24
|
+
* `Path<T>` extractor vs Python's `pathlib.Path` constructor).
|
|
25
|
+
*/
|
|
26
|
+
languages?: SupportedLanguage[];
|
|
20
27
|
note?: string;
|
|
21
28
|
}
|
|
22
29
|
export interface SinkConfig {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAMhG,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAE5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAIhB,UAAU,CAAC,EAAE,MAAM,CAAC;IAIpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IAGnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAChC;;;;;;;;;OASG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAMD;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;IACZ,0DAA0D;IAC1D,KAAK,EAAE,UAAU,CAAC;IAClB,+DAA+D;IAC/D,QAAQ,EAAE,QAAQ,CAAC;IACnB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,IAAI,EAAE,SAAS,GAAG,YAAY,GAAG,cAAc,CAAC;IAChD;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAMhG,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAE5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAIhB,UAAU,CAAC,EAAE,MAAM,CAAC;IAIpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IAGnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAEhC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAChC;;;;;;;;;OASG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAMD;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;IACZ,0DAA0D;IAC1D,KAAK,EAAE,UAAU,CAAC;IAClB,+DAA+D;IAC/D,QAAQ,EAAE,QAAQ,CAAC;IACnB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,IAAI,EAAE,SAAS,GAAG,YAAY,GAAG,cAAc,CAAC;IAChD;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "circle-ir",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.58.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",
|