circle-ir 4.16.0 → 4.17.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/constant-propagation/index.d.ts +2 -0
- package/dist/analysis/constant-propagation/index.d.ts.map +1 -1
- package/dist/analysis/constant-propagation/index.js +10 -0
- package/dist/analysis/constant-propagation/index.js.map +1 -1
- package/dist/analysis/constant-propagation/propagator.d.ts +11 -0
- package/dist/analysis/constant-propagation/propagator.d.ts.map +1 -1
- package/dist/analysis/constant-propagation/propagator.js +125 -20
- package/dist/analysis/constant-propagation/propagator.js.map +1 -1
- package/dist/analysis/constant-propagation/types.d.ts +2 -0
- package/dist/analysis/constant-propagation/types.d.ts.map +1 -1
- package/dist/analysis/constant-propagation.d.ts +1 -1
- package/dist/analysis/constant-propagation.d.ts.map +1 -1
- package/dist/analysis/constant-propagation.js +1 -1
- package/dist/analysis/constant-propagation.js.map +1 -1
- package/dist/analysis/interprocedural.d.ts.map +1 -1
- package/dist/analysis/interprocedural.js +37 -8
- package/dist/analysis/interprocedural.js.map +1 -1
- package/dist/analysis/passes/cross-file-pass.d.ts.map +1 -1
- package/dist/analysis/passes/cross-file-pass.js +3 -1
- package/dist/analysis/passes/cross-file-pass.js.map +1 -1
- package/dist/analysis/passes/csharp-sanitizer-credit.d.ts +13 -0
- package/dist/analysis/passes/csharp-sanitizer-credit.d.ts.map +1 -1
- package/dist/analysis/passes/csharp-sanitizer-credit.js +48 -0
- package/dist/analysis/passes/csharp-sanitizer-credit.js.map +1 -1
- package/dist/analysis/passes/language-sources-pass.d.ts.map +1 -1
- package/dist/analysis/passes/language-sources-pass.js +80 -8
- package/dist/analysis/passes/language-sources-pass.js.map +1 -1
- package/dist/analysis/passes/param-source-flow-gate-pass.d.ts.map +1 -1
- package/dist/analysis/passes/param-source-flow-gate-pass.js +17 -1
- package/dist/analysis/passes/param-source-flow-gate-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 +19 -3
- 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 +205 -22
- package/dist/analysis/passes/taint-propagation-pass.js.map +1 -1
- package/dist/analysis/rust-literal-guard.d.ts.map +1 -1
- package/dist/analysis/rust-literal-guard.js +100 -1
- package/dist/analysis/rust-literal-guard.js.map +1 -1
- package/dist/analysis/taint-matcher.d.ts.map +1 -1
- package/dist/analysis/taint-matcher.js +1 -0
- package/dist/analysis/taint-matcher.js.map +1 -1
- package/dist/browser/circle-ir.js +561 -41
- package/dist/core/circle-ir-core.cjs +149 -17
- package/dist/core/circle-ir-core.js +149 -17
- package/dist/core/extractors/types.js +53 -9
- package/dist/core/extractors/types.js.map +1 -1
- package/dist/navigation/navigation-index.d.ts +40 -1
- package/dist/navigation/navigation-index.d.ts.map +1 -1
- package/dist/navigation/navigation-index.js +300 -45
- package/dist/navigation/navigation-index.js.map +1 -1
- package/dist/resolution/cross-file.d.ts +9 -0
- package/dist/resolution/cross-file.d.ts.map +1 -1
- package/dist/resolution/cross-file.js +134 -0
- package/dist/resolution/cross-file.js.map +1 -1
- package/dist/types/index.d.ts +18 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1701,6 +1701,9 @@ function findCSharpRequestSources(sourceCode, language) {
|
|
|
1701
1701
|
// cognium-dev#638 step 3 — `box.value = req.QueryString["k"]` seeds the
|
|
1702
1702
|
// container local so cross-file calls that pass `box` carry taint.
|
|
1703
1703
|
const memberFieldAssignRe = /^\s*([A-Za-z_]\w*)\.([A-Za-z_]\w*)\s*=\s*(.+?);?\s*$/;
|
|
1704
|
+
// cognium-dev#638 step 5 — `list.Add(req.QueryString["k"])` seeds the list
|
|
1705
|
+
// local so cross-file calls that pass `list` carry taint into callee reads.
|
|
1706
|
+
const collectionAddRe = /^\s*([A-Za-z_]\w*)\s*\.\s*Add\s*\(\s*(.+?)\s*\)\s*;?\s*$/;
|
|
1704
1707
|
// `Request.*` is the inherited controller member. A parameter typed
|
|
1705
1708
|
// `HttpRequest` / `HttpRequestBase` is the same surface under whatever
|
|
1706
1709
|
// name the method uses (`req` in Juliet) — cognium-dev#501.
|
|
@@ -1869,6 +1872,25 @@ function findCSharpRequestSources(sourceCode, language) {
|
|
|
1869
1872
|
continue;
|
|
1870
1873
|
}
|
|
1871
1874
|
}
|
|
1875
|
+
const addEl = collectionAddRe.exec(stmt);
|
|
1876
|
+
if (addEl) {
|
|
1877
|
+
const [, baseName, rhs] = addEl;
|
|
1878
|
+
const type = classify(rhs);
|
|
1879
|
+
if (type && baseName) {
|
|
1880
|
+
const lineNumber = i + 1;
|
|
1881
|
+
if (!sources.some(s => s.line === lineNumber && s.variable === baseName)) {
|
|
1882
|
+
sources.push({
|
|
1883
|
+
type,
|
|
1884
|
+
location: `${baseName}.Add(${rhs.trim().substring(0, 50)}${rhs.length > 50 ? '...' : ''})`,
|
|
1885
|
+
severity: type === 'db_input' ? 'medium' : 'high',
|
|
1886
|
+
line: lineNumber,
|
|
1887
|
+
confidence: 1.0,
|
|
1888
|
+
variable: baseName,
|
|
1889
|
+
});
|
|
1890
|
+
}
|
|
1891
|
+
continue;
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1872
1894
|
const m = assignRe.exec(stmt);
|
|
1873
1895
|
// cognium-dev#502 — `assignRe` is anchored and greedy, so on a one-line
|
|
1874
1896
|
// block header that also contains the real assignment
|
|
@@ -7446,10 +7468,14 @@ function findCSharpEarlyReturnGuardSanitizers(code, language) {
|
|
|
7446
7468
|
const lines = code.split('\n');
|
|
7447
7469
|
const terminatorRe = /\b(throw|return)\b/;
|
|
7448
7470
|
// Allow-list membership, rejecting form:
|
|
7449
|
-
// if (Array.IndexOf(Allowed, x) < 0) return;
|
|
7471
|
+
// if (Array.IndexOf(Allowed, x) < 0) return; (also System.Array, == -1)
|
|
7450
7472
|
// if (!Allowed.Contains(x)) return;
|
|
7473
|
+
// cognium-dev#809: the IndexOf form credits only a `static readonly`
|
|
7474
|
+
// string-literal array field the file never writes (see
|
|
7475
|
+
// `collectCSharpLiteralArrayFields`); any other array may hold the value.
|
|
7476
|
+
const literalArrays = collectCSharpLiteralArrayFields(code);
|
|
7477
|
+
const indexOfRe = /\bif\s*\(\s*(?:System\s*\.\s*)?Array\s*\.\s*IndexOf\s*\(\s*([A-Za-z_]\w*)\s*,\s*([A-Za-z_][\w.]*)\s*\)\s*(?:<\s*0|==\s*-\s*1)\s*\)/;
|
|
7451
7478
|
const allowlistRes = [
|
|
7452
|
-
/\bif\s*\(\s*Array\s*\.\s*IndexOf\s*\([^,]+,\s*([A-Za-z_][\w.]*)\s*\)\s*<\s*0\s*\)/,
|
|
7453
7479
|
/\bif\s*\(\s*!\s*[A-Za-z_][\w.]*\s*\.\s*Contains\s*\(\s*([A-Za-z_][\w.]*)\s*\)\s*\)/,
|
|
7454
7480
|
];
|
|
7455
7481
|
// Character-class validation, rejecting form:
|
|
@@ -7457,13 +7483,17 @@ function findCSharpEarlyReturnGuardSanitizers(code, language) {
|
|
|
7457
7483
|
const charClassRe = /\bif\s*\(\s*!\s*([A-Za-z_][\w.]*)\s*\.\s*All\s*\(\s*char\s*\.\s*Is[A-Za-z]+\s*\)\s*\)/;
|
|
7458
7484
|
for (let i = 0; i < lines.length; i++) {
|
|
7459
7485
|
let guardedExpr = null;
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7486
|
+
const im = indexOfRe.exec(lines[i]);
|
|
7487
|
+
if (im && literalArrays.has(im[1]))
|
|
7488
|
+
guardedExpr = im[2];
|
|
7489
|
+
if (!guardedExpr)
|
|
7490
|
+
for (const re of allowlistRes) {
|
|
7491
|
+
const m = re.exec(lines[i]);
|
|
7492
|
+
if (m) {
|
|
7493
|
+
guardedExpr = m[1];
|
|
7494
|
+
break;
|
|
7495
|
+
}
|
|
7465
7496
|
}
|
|
7466
|
-
}
|
|
7467
7497
|
if (!guardedExpr) {
|
|
7468
7498
|
const m = charClassRe.exec(lines[i]);
|
|
7469
7499
|
if (m)
|
|
@@ -7507,6 +7537,10 @@ function findCSharpEarlyReturnGuardSanitizers(code, language) {
|
|
|
7507
7537
|
const a = assignRe.exec(lines[l]);
|
|
7508
7538
|
if (a && mentions(a[2]))
|
|
7509
7539
|
guarded.add(a[1]);
|
|
7540
|
+
// cognium-dev#809: a reassignment from anything unguarded ends the
|
|
7541
|
+
// credit (`target = Console.ReadLine();` after the guard).
|
|
7542
|
+
else if (a)
|
|
7543
|
+
guarded.delete(a[1]);
|
|
7510
7544
|
if (mentions(lines[l])) {
|
|
7511
7545
|
sanitizers.push({
|
|
7512
7546
|
type: 'csharp_early_return_guard',
|
|
@@ -7520,6 +7554,44 @@ function findCSharpEarlyReturnGuardSanitizers(code, language) {
|
|
|
7520
7554
|
}
|
|
7521
7555
|
return sanitizers;
|
|
7522
7556
|
}
|
|
7557
|
+
/**
|
|
7558
|
+
* cognium-dev#809 — names of `static readonly string[]` fields initialised
|
|
7559
|
+
* with string literals only, that the file never writes:
|
|
7560
|
+
*
|
|
7561
|
+
* private static readonly string[] KnownHosts = { "a.example", "b.example" };
|
|
7562
|
+
*
|
|
7563
|
+
* Past `if (Array.IndexOf(KnownHosts, x) < 0) throw …;`, `x` is one of those
|
|
7564
|
+
* literals. The C# counterpart of the Python literal-collection membership
|
|
7565
|
+
* guard (#563) and the Rust literal-equality guard (#293).
|
|
7566
|
+
*
|
|
7567
|
+
* `readonly` stops the field being rebound outside an initialiser, but array
|
|
7568
|
+
* elements stay writable, so any element store, `ref`/`out` pass,
|
|
7569
|
+
* `SetValue`, `Array.<mutator>(…)` naming the field, or plain assignment
|
|
7570
|
+
* after the declaration disqualifies it.
|
|
7571
|
+
*/
|
|
7572
|
+
function collectCSharpLiteralArrayFields(code) {
|
|
7573
|
+
const names = new Set();
|
|
7574
|
+
const lit = String.raw `(?:@"(?:[^"]|"")*"|"(?:[^"\\\n]|\\.)*")`;
|
|
7575
|
+
const elems = new RegExp(String.raw `^\s*${lit}(?:\s*,\s*${lit})*\s*,?\s*$`);
|
|
7576
|
+
const declRe = /((?:\b(?:public|private|protected|internal|static|readonly)\s+)+)string\s*\[\s*\]\s+([A-Za-z_]\w*)\s*=\s*(?:new\s+(?:string\s*)?\[\s*\]\s*)?\{([^{}]*)\}\s*;/g;
|
|
7577
|
+
for (const m of code.matchAll(declRe)) {
|
|
7578
|
+
const mods = m[1];
|
|
7579
|
+
const name = m[2];
|
|
7580
|
+
if (!/\bstatic\b/.test(mods) || !/\breadonly\b/.test(mods))
|
|
7581
|
+
continue;
|
|
7582
|
+
if (!elems.test(m[3]))
|
|
7583
|
+
continue;
|
|
7584
|
+
const rest = code.slice(0, m.index) + code.slice(m.index + m[0].length);
|
|
7585
|
+
const written = new RegExp(String.raw `\b${name}\s*(?:\[[^\]]*\]\s*)?(?:[-+*/%&|^]|\?\?)?=(?!=)` +
|
|
7586
|
+
String.raw `|\b(?:ref|out)\s+${name}\b` +
|
|
7587
|
+
String.raw `|\b${name}\s*\.\s*SetValue\s*\(` +
|
|
7588
|
+
String.raw `|\bArray\s*\.\s*(?:Clear|Copy|ConstrainedCopy|Fill|Resize|Reverse|Sort)\s*\([^;]*\b${name}\b`);
|
|
7589
|
+
if (written.test(rest))
|
|
7590
|
+
continue;
|
|
7591
|
+
names.add(name);
|
|
7592
|
+
}
|
|
7593
|
+
return names;
|
|
7594
|
+
}
|
|
7523
7595
|
function findCSharpFullPathStartsWithGuardSanitizers(code) {
|
|
7524
7596
|
const sanitizers = [];
|
|
7525
7597
|
const lines = code.split('\n');
|