circle-ir 3.74.0 → 3.77.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/config-loader.d.ts.map +1 -1
- package/dist/analysis/config-loader.js +12 -0
- package/dist/analysis/config-loader.js.map +1 -1
- package/dist/analysis/passes/jwt-verify-disabled-pass.d.ts.map +1 -1
- package/dist/analysis/passes/jwt-verify-disabled-pass.js +18 -6
- package/dist/analysis/passes/jwt-verify-disabled-pass.js.map +1 -1
- package/dist/analysis/passes/taint-propagation-pass.js +59 -0
- package/dist/analysis/passes/taint-propagation-pass.js.map +1 -1
- package/dist/analysis/passes/weak-random-pass.d.ts.map +1 -1
- package/dist/analysis/passes/weak-random-pass.js +11 -0
- package/dist/analysis/passes/weak-random-pass.js.map +1 -1
- package/dist/analysis/taint-matcher.d.ts.map +1 -1
- package/dist/analysis/taint-matcher.js +9 -0
- package/dist/analysis/taint-matcher.js.map +1 -1
- package/dist/browser/circle-ir.js +58 -1
- package/dist/core/circle-ir-core.cjs +16 -0
- package/dist/core/circle-ir-core.js +16 -0
- package/package.json +1 -1
|
@@ -12413,6 +12413,18 @@ var DEFAULT_SINKS = [
|
|
|
12413
12413
|
// value position so a tainted variable is detected.
|
|
12414
12414
|
{ method: "Set", class: "Header", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["go"] },
|
|
12415
12415
|
{ method: "Add", class: "Header", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["go"] },
|
|
12416
|
+
// Python: Flask/Werkzeug/FastAPI/Django response header sinks (CWE-113).
|
|
12417
|
+
// Subscript assignment (`resp.headers['X-A'] = name`) is NOT covered because
|
|
12418
|
+
// the IR does not emit subscript writes as calls — a known limitation, see
|
|
12419
|
+
// cognium-dev #111. The method-call forms below ARE captured (receiver
|
|
12420
|
+
// suffix-match on `.headers` via receiverMightBeClass).
|
|
12421
|
+
{ method: "set", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
12422
|
+
{ method: "add", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
12423
|
+
{ method: "setdefault", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
12424
|
+
{ method: "extend", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [0], languages: ["python"] },
|
|
12425
|
+
{ method: "__setitem__", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
12426
|
+
// Flask/Werkzeug response.set_cookie(name, value, ...) — value is CRLF-sensitive.
|
|
12427
|
+
{ method: "set_cookie", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
12416
12428
|
// Mass-assignment (CWE-915 / CWE-1321) — Sprint 6, #86; cognium-dev #68 Sprint 10.
|
|
12417
12429
|
// JS Object.assign(target, ...sources), `_.merge`, `_.extend`, `$.extend`,
|
|
12418
12430
|
// `Object.defineProperty` — when fed an attacker-controlled bag, they write
|
|
@@ -13539,6 +13551,10 @@ function receiverMightBeClass(receiver, className) {
|
|
|
13539
13551
|
}
|
|
13540
13552
|
}
|
|
13541
13553
|
}
|
|
13554
|
+
const chainedCallSuffix = `.${className}()`;
|
|
13555
|
+
if (receiver.endsWith(chainedCallSuffix) || receiver.toLowerCase().endsWith(chainedCallSuffix.toLowerCase())) {
|
|
13556
|
+
return true;
|
|
13557
|
+
}
|
|
13542
13558
|
if (receiver.includes("::")) {
|
|
13543
13559
|
const scopePrefix = receiver.match(/^(\w+)::/);
|
|
13544
13560
|
if (scopePrefix) {
|
|
@@ -24641,6 +24657,43 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
24641
24657
|
}
|
|
24642
24658
|
}
|
|
24643
24659
|
}
|
|
24660
|
+
const aliasChains = [];
|
|
24661
|
+
{
|
|
24662
|
+
const codeLines2 = code.split("\n");
|
|
24663
|
+
for (let i2 = 0; i2 < codeLines2.length; i2++) {
|
|
24664
|
+
const ln = codeLines2[i2];
|
|
24665
|
+
if (ln.trimStart().startsWith("#")) continue;
|
|
24666
|
+
const m = ln.match(/^\s*([\p{L}\p{N}_]+)\s*=\s*([\p{L}\p{N}_]+)\s*$/u);
|
|
24667
|
+
if (!m) continue;
|
|
24668
|
+
const lineNum = i2 + 1;
|
|
24669
|
+
const lhs = m[1];
|
|
24670
|
+
if (derived.get(lhs) !== lineNum) continue;
|
|
24671
|
+
aliasChains.push({ lhs, upstream: m[2], line: lineNum });
|
|
24672
|
+
}
|
|
24673
|
+
}
|
|
24674
|
+
if (aliasChains.length > 0) {
|
|
24675
|
+
let changed = true;
|
|
24676
|
+
let guard = 0;
|
|
24677
|
+
while (changed && guard < aliasChains.length + 2) {
|
|
24678
|
+
changed = false;
|
|
24679
|
+
guard++;
|
|
24680
|
+
for (const { lhs, upstream } of aliasChains) {
|
|
24681
|
+
const upCov = aliasSanitizedFor.get(upstream);
|
|
24682
|
+
if (!upCov || upCov.size === 0) continue;
|
|
24683
|
+
let downCov = aliasSanitizedFor.get(lhs);
|
|
24684
|
+
if (!downCov) {
|
|
24685
|
+
downCov = /* @__PURE__ */ new Set();
|
|
24686
|
+
aliasSanitizedFor.set(lhs, downCov);
|
|
24687
|
+
}
|
|
24688
|
+
for (const t of upCov) {
|
|
24689
|
+
if (!downCov.has(t)) {
|
|
24690
|
+
downCov.add(t);
|
|
24691
|
+
changed = true;
|
|
24692
|
+
}
|
|
24693
|
+
}
|
|
24694
|
+
}
|
|
24695
|
+
}
|
|
24696
|
+
}
|
|
24644
24697
|
}
|
|
24645
24698
|
}
|
|
24646
24699
|
if (language === "rust" && typeof code === "string" && sourcesWithVar.length > 0) {
|
|
@@ -29758,6 +29811,10 @@ var WeakRandomPass = class {
|
|
|
29758
29811
|
return `${rt}.${method}`;
|
|
29759
29812
|
}
|
|
29760
29813
|
}
|
|
29814
|
+
if (JAVA_RANDOM_METHODS.has(method)) {
|
|
29815
|
+
if (/^new\s+Random\s*\(/.test(receiver)) return `new Random.${method}`;
|
|
29816
|
+
if (/^new\s+SplittableRandom\s*\(/.test(receiver)) return `new SplittableRandom.${method}`;
|
|
29817
|
+
}
|
|
29761
29818
|
if (JAVA_RANDOM_METHODS.has(method) && /ThreadLocalRandom\.current\(\)/.test(receiver)) {
|
|
29762
29819
|
return `ThreadLocalRandom.current.${method}`;
|
|
29763
29820
|
}
|
|
@@ -30576,7 +30633,7 @@ var JwtVerifyDisabledPass = class {
|
|
|
30576
30633
|
out2.push({ pattern: "Algorithm.none()", api: "JWT.require" });
|
|
30577
30634
|
}
|
|
30578
30635
|
}
|
|
30579
|
-
if (method === "parse" && receiver
|
|
30636
|
+
if (method === "parse" && /\bJwts\s*\.\s*parser\s*\(/.test(receiver)) {
|
|
30580
30637
|
out2.push({ pattern: "parse() instead of parseClaimsJws()", api: "Jwts.parser().parse" });
|
|
30581
30638
|
}
|
|
30582
30639
|
return out2;
|
|
@@ -11795,6 +11795,18 @@ var DEFAULT_SINKS = [
|
|
|
11795
11795
|
// value position so a tainted variable is detected.
|
|
11796
11796
|
{ method: "Set", class: "Header", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["go"] },
|
|
11797
11797
|
{ method: "Add", class: "Header", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["go"] },
|
|
11798
|
+
// Python: Flask/Werkzeug/FastAPI/Django response header sinks (CWE-113).
|
|
11799
|
+
// Subscript assignment (`resp.headers['X-A'] = name`) is NOT covered because
|
|
11800
|
+
// the IR does not emit subscript writes as calls — a known limitation, see
|
|
11801
|
+
// cognium-dev #111. The method-call forms below ARE captured (receiver
|
|
11802
|
+
// suffix-match on `.headers` via receiverMightBeClass).
|
|
11803
|
+
{ method: "set", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
11804
|
+
{ method: "add", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
11805
|
+
{ method: "setdefault", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
11806
|
+
{ method: "extend", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [0], languages: ["python"] },
|
|
11807
|
+
{ method: "__setitem__", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
11808
|
+
// Flask/Werkzeug response.set_cookie(name, value, ...) — value is CRLF-sensitive.
|
|
11809
|
+
{ method: "set_cookie", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
11798
11810
|
// Mass-assignment (CWE-915 / CWE-1321) — Sprint 6, #86; cognium-dev #68 Sprint 10.
|
|
11799
11811
|
// JS Object.assign(target, ...sources), `_.merge`, `_.extend`, `$.extend`,
|
|
11800
11812
|
// `Object.defineProperty` — when fed an attacker-controlled bag, they write
|
|
@@ -12834,6 +12846,10 @@ function receiverMightBeClass(receiver, className) {
|
|
|
12834
12846
|
}
|
|
12835
12847
|
}
|
|
12836
12848
|
}
|
|
12849
|
+
const chainedCallSuffix = `.${className}()`;
|
|
12850
|
+
if (receiver.endsWith(chainedCallSuffix) || receiver.toLowerCase().endsWith(chainedCallSuffix.toLowerCase())) {
|
|
12851
|
+
return true;
|
|
12852
|
+
}
|
|
12837
12853
|
if (receiver.includes("::")) {
|
|
12838
12854
|
const scopePrefix = receiver.match(/^(\w+)::/);
|
|
12839
12855
|
if (scopePrefix) {
|
|
@@ -11729,6 +11729,18 @@ var DEFAULT_SINKS = [
|
|
|
11729
11729
|
// value position so a tainted variable is detected.
|
|
11730
11730
|
{ method: "Set", class: "Header", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["go"] },
|
|
11731
11731
|
{ method: "Add", class: "Header", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["go"] },
|
|
11732
|
+
// Python: Flask/Werkzeug/FastAPI/Django response header sinks (CWE-113).
|
|
11733
|
+
// Subscript assignment (`resp.headers['X-A'] = name`) is NOT covered because
|
|
11734
|
+
// the IR does not emit subscript writes as calls — a known limitation, see
|
|
11735
|
+
// cognium-dev #111. The method-call forms below ARE captured (receiver
|
|
11736
|
+
// suffix-match on `.headers` via receiverMightBeClass).
|
|
11737
|
+
{ method: "set", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
11738
|
+
{ method: "add", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
11739
|
+
{ method: "setdefault", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
11740
|
+
{ method: "extend", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [0], languages: ["python"] },
|
|
11741
|
+
{ method: "__setitem__", class: "headers", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
11742
|
+
// Flask/Werkzeug response.set_cookie(name, value, ...) — value is CRLF-sensitive.
|
|
11743
|
+
{ method: "set_cookie", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
11732
11744
|
// Mass-assignment (CWE-915 / CWE-1321) — Sprint 6, #86; cognium-dev #68 Sprint 10.
|
|
11733
11745
|
// JS Object.assign(target, ...sources), `_.merge`, `_.extend`, `$.extend`,
|
|
11734
11746
|
// `Object.defineProperty` — when fed an attacker-controlled bag, they write
|
|
@@ -12768,6 +12780,10 @@ function receiverMightBeClass(receiver, className) {
|
|
|
12768
12780
|
}
|
|
12769
12781
|
}
|
|
12770
12782
|
}
|
|
12783
|
+
const chainedCallSuffix = `.${className}()`;
|
|
12784
|
+
if (receiver.endsWith(chainedCallSuffix) || receiver.toLowerCase().endsWith(chainedCallSuffix.toLowerCase())) {
|
|
12785
|
+
return true;
|
|
12786
|
+
}
|
|
12771
12787
|
if (receiver.includes("::")) {
|
|
12772
12788
|
const scopePrefix = receiver.match(/^(\w+)::/);
|
|
12773
12789
|
if (scopePrefix) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "circle-ir",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.77.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",
|