circle-ir 4.17.0 → 4.18.1
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/advisories.d.ts +186 -0
- package/dist/analysis/advisories.d.ts.map +1 -0
- package/dist/analysis/advisories.js +391 -0
- package/dist/analysis/advisories.js.map +1 -0
- package/dist/analysis/comment-lines.d.ts +14 -0
- package/dist/analysis/comment-lines.d.ts.map +1 -0
- package/dist/analysis/comment-lines.js +34 -0
- package/dist/analysis/comment-lines.js.map +1 -0
- package/dist/analysis/config-loader.d.ts.map +1 -1
- package/dist/analysis/config-loader.js +59 -5
- package/dist/analysis/config-loader.js.map +1 -1
- package/dist/analysis/constant-caller-gate.d.ts +2 -2
- package/dist/analysis/constant-caller-gate.d.ts.map +1 -1
- package/dist/analysis/constant-caller-gate.js +205 -29
- package/dist/analysis/constant-caller-gate.js.map +1 -1
- package/dist/analysis/constant-propagation/propagator.d.ts +4 -0
- package/dist/analysis/constant-propagation/propagator.d.ts.map +1 -1
- package/dist/analysis/constant-propagation/propagator.js +99 -0
- package/dist/analysis/constant-propagation/propagator.js.map +1 -1
- package/dist/analysis/entry-point-detection.d.ts.map +1 -1
- package/dist/analysis/entry-point-detection.js +72 -0
- package/dist/analysis/entry-point-detection.js.map +1 -1
- package/dist/analysis/interprocedural.d.ts.map +1 -1
- package/dist/analysis/interprocedural.js +75 -8
- package/dist/analysis/interprocedural.js.map +1 -1
- package/dist/analysis/maven-declared.d.ts +72 -0
- package/dist/analysis/maven-declared.d.ts.map +1 -0
- package/dist/analysis/maven-declared.js +216 -0
- package/dist/analysis/maven-declared.js.map +1 -0
- package/dist/analysis/maven-version.d.ts +28 -0
- package/dist/analysis/maven-version.d.ts.map +1 -0
- package/dist/analysis/maven-version.js +172 -0
- package/dist/analysis/maven-version.js.map +1 -0
- package/dist/analysis/passes/constant-propagation-pass.d.ts.map +1 -1
- package/dist/analysis/passes/constant-propagation-pass.js +29 -1
- package/dist/analysis/passes/constant-propagation-pass.js.map +1 -1
- package/dist/analysis/passes/cross-file-pass.d.ts.map +1 -1
- package/dist/analysis/passes/cross-file-pass.js +81 -1
- package/dist/analysis/passes/cross-file-pass.js.map +1 -1
- package/dist/analysis/passes/csharp-sanitizer-credit.d.ts +7 -0
- package/dist/analysis/passes/csharp-sanitizer-credit.d.ts.map +1 -1
- package/dist/analysis/passes/csharp-sanitizer-credit.js +44 -1
- package/dist/analysis/passes/csharp-sanitizer-credit.js.map +1 -1
- package/dist/analysis/passes/insecure-cookie-pass.d.ts +2 -0
- package/dist/analysis/passes/insecure-cookie-pass.d.ts.map +1 -1
- package/dist/analysis/passes/insecure-cookie-pass.js +25 -3
- package/dist/analysis/passes/insecure-cookie-pass.js.map +1 -1
- package/dist/analysis/passes/interprocedural-pass.d.ts +11 -14
- package/dist/analysis/passes/interprocedural-pass.d.ts.map +1 -1
- package/dist/analysis/passes/interprocedural-pass.js +562 -0
- package/dist/analysis/passes/interprocedural-pass.js.map +1 -1
- package/dist/analysis/passes/language-sources-pass.d.ts +18 -1
- package/dist/analysis/passes/language-sources-pass.d.ts.map +1 -1
- package/dist/analysis/passes/language-sources-pass.js +1057 -14
- 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 +66 -3
- package/dist/analysis/passes/param-source-flow-gate-pass.js.map +1 -1
- package/dist/analysis/passes/sink-filter-pass.d.ts +44 -2
- package/dist/analysis/passes/sink-filter-pass.d.ts.map +1 -1
- package/dist/analysis/passes/sink-filter-pass.js +690 -12
- 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 +133 -10
- package/dist/analysis/passes/taint-propagation-pass.js.map +1 -1
- package/dist/analysis/passes/tls-verify-disabled-pass.d.ts +18 -0
- package/dist/analysis/passes/tls-verify-disabled-pass.d.ts.map +1 -1
- package/dist/analysis/passes/tls-verify-disabled-pass.js +161 -0
- package/dist/analysis/passes/tls-verify-disabled-pass.js.map +1 -1
- package/dist/analysis/passes/weak-random-pass.d.ts +6 -0
- package/dist/analysis/passes/weak-random-pass.d.ts.map +1 -1
- package/dist/analysis/passes/weak-random-pass.js +29 -0
- package/dist/analysis/passes/weak-random-pass.js.map +1 -1
- package/dist/analysis/promote-cross-file-flows.d.ts +17 -0
- package/dist/analysis/promote-cross-file-flows.d.ts.map +1 -0
- package/dist/analysis/promote-cross-file-flows.js +32 -0
- package/dist/analysis/promote-cross-file-flows.js.map +1 -0
- package/dist/analysis/sbom.d.ts +100 -0
- package/dist/analysis/sbom.d.ts.map +1 -1
- package/dist/analysis/sbom.js +514 -3
- package/dist/analysis/sbom.js.map +1 -1
- package/dist/analysis/semver-version.d.ts +30 -0
- package/dist/analysis/semver-version.d.ts.map +1 -0
- package/dist/analysis/semver-version.js +76 -0
- package/dist/analysis/semver-version.js.map +1 -0
- package/dist/analysis/taint-matcher.d.ts +5 -0
- package/dist/analysis/taint-matcher.d.ts.map +1 -1
- package/dist/analysis/taint-matcher.js +225 -4
- package/dist/analysis/taint-matcher.js.map +1 -1
- package/dist/analyzer.d.ts +57 -0
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +69 -6
- package/dist/analyzer.js.map +1 -1
- package/dist/browser/circle-ir.js +2936 -291
- package/dist/core/circle-ir-core.cjs +634 -203
- package/dist/core/circle-ir-core.js +634 -203
- package/dist/core/extractors/dfg.js +205 -2
- package/dist/core/extractors/dfg.js.map +1 -1
- package/dist/core/extractors/ts-declaration-detail.d.ts +39 -0
- package/dist/core/extractors/ts-declaration-detail.d.ts.map +1 -0
- package/dist/core/extractors/ts-declaration-detail.js +266 -0
- package/dist/core/extractors/ts-declaration-detail.js.map +1 -0
- package/dist/graph/analysis-pass.d.ts +4 -1
- package/dist/graph/analysis-pass.d.ts.map +1 -1
- package/dist/graph/analysis-pass.js +4 -1
- package/dist/graph/analysis-pass.js.map +1 -1
- package/dist/graph-facts/dead-code.d.ts +62 -0
- package/dist/graph-facts/dead-code.d.ts.map +1 -0
- package/dist/graph-facts/dead-code.js +90 -0
- package/dist/graph-facts/dead-code.js.map +1 -0
- package/dist/graph-facts/dependency-calls.d.ts +86 -0
- package/dist/graph-facts/dependency-calls.d.ts.map +1 -0
- package/dist/graph-facts/dependency-calls.js +93 -0
- package/dist/graph-facts/dependency-calls.js.map +1 -0
- package/dist/graph-facts/index.d.ts +10 -0
- package/dist/graph-facts/index.d.ts.map +1 -0
- package/dist/graph-facts/index.js +10 -0
- package/dist/graph-facts/index.js.map +1 -0
- package/dist/graph-facts/maven-packages.d.ts +42 -0
- package/dist/graph-facts/maven-packages.d.ts.map +1 -0
- package/dist/graph-facts/maven-packages.js +133 -0
- package/dist/graph-facts/maven-packages.js.map +1 -0
- package/dist/graph-facts/reach.d.ts +203 -0
- package/dist/graph-facts/reach.d.ts.map +1 -0
- package/dist/graph-facts/reach.js +219 -0
- package/dist/graph-facts/reach.js.map +1 -0
- package/dist/graph-facts/removal-reach.d.ts +73 -0
- package/dist/graph-facts/removal-reach.d.ts.map +1 -0
- package/dist/graph-facts/removal-reach.js +64 -0
- package/dist/graph-facts/removal-reach.js.map +1 -0
- package/dist/index.d.ts +21 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -3
- package/dist/index.js.map +1 -1
- package/dist/navigation/go-graph.d.ts +68 -0
- package/dist/navigation/go-graph.d.ts.map +1 -0
- package/dist/navigation/go-graph.js +753 -0
- package/dist/navigation/go-graph.js.map +1 -0
- package/dist/navigation/index.d.ts +7 -1
- package/dist/navigation/index.d.ts.map +1 -1
- package/dist/navigation/index.js +6 -0
- package/dist/navigation/index.js.map +1 -1
- package/dist/navigation/java-entry-tables.d.ts +43 -0
- package/dist/navigation/java-entry-tables.d.ts.map +1 -0
- package/dist/navigation/java-entry-tables.js +56 -0
- package/dist/navigation/java-entry-tables.js.map +1 -0
- package/dist/navigation/java-graph.d.ts +64 -0
- package/dist/navigation/java-graph.d.ts.map +1 -0
- package/dist/navigation/java-graph.js +466 -0
- package/dist/navigation/java-graph.js.map +1 -0
- package/dist/navigation/navigation-index.d.ts +51 -1
- package/dist/navigation/navigation-index.d.ts.map +1 -1
- package/dist/navigation/navigation-index.js +72 -0
- package/dist/navigation/navigation-index.js.map +1 -1
- package/dist/navigation/python-graph.d.ts +73 -0
- package/dist/navigation/python-graph.d.ts.map +1 -0
- package/dist/navigation/python-graph.js +867 -0
- package/dist/navigation/python-graph.js.map +1 -0
- package/dist/navigation/ts-call-edges.d.ts +193 -0
- package/dist/navigation/ts-call-edges.d.ts.map +1 -0
- package/dist/navigation/ts-call-edges.js +2089 -0
- package/dist/navigation/ts-call-edges.js.map +1 -0
- package/dist/navigation/ts-entry-tables.d.ts +88 -0
- package/dist/navigation/ts-entry-tables.d.ts.map +1 -0
- package/dist/navigation/ts-entry-tables.js +50 -0
- package/dist/navigation/ts-entry-tables.js.map +1 -0
- package/dist/path-set/branches.d.ts +52 -0
- package/dist/path-set/branches.d.ts.map +1 -0
- package/dist/path-set/branches.js +124 -0
- package/dist/path-set/branches.js.map +1 -0
- package/dist/path-set/finding-diff.d.ts +63 -0
- package/dist/path-set/finding-diff.d.ts.map +1 -0
- package/dist/path-set/finding-diff.js +150 -0
- package/dist/path-set/finding-diff.js.map +1 -0
- package/dist/path-set/index.d.ts +18 -0
- package/dist/path-set/index.d.ts.map +1 -0
- package/dist/path-set/index.js +12 -0
- package/dist/path-set/index.js.map +1 -0
- package/dist/path-set/line-diff.d.ts +19 -0
- package/dist/path-set/line-diff.d.ts.map +1 -0
- package/dist/path-set/line-diff.js +98 -0
- package/dist/path-set/line-diff.js.map +1 -0
- package/dist/path-set/path-set.d.ts +88 -0
- package/dist/path-set/path-set.d.ts.map +1 -0
- package/dist/path-set/path-set.js +716 -0
- package/dist/path-set/path-set.js.map +1 -0
- package/dist/path-set/templates.d.ts +42 -0
- package/dist/path-set/templates.d.ts.map +1 -0
- package/dist/path-set/templates.js +119 -0
- package/dist/path-set/templates.js.map +1 -0
- package/dist/path-set/types.d.ts +195 -0
- package/dist/path-set/types.d.ts.map +1 -0
- package/dist/path-set/types.js +8 -0
- package/dist/path-set/types.js.map +1 -0
- package/dist/remedy-class/index.d.ts +12 -0
- package/dist/remedy-class/index.d.ts.map +1 -0
- package/dist/remedy-class/index.js +9 -0
- package/dist/remedy-class/index.js.map +1 -0
- package/dist/remedy-class/match.d.ts +165 -0
- package/dist/remedy-class/match.d.ts.map +1 -0
- package/dist/remedy-class/match.js +705 -0
- package/dist/remedy-class/match.js.map +1 -0
- package/dist/remedy-class/output-context.d.ts +25 -0
- package/dist/remedy-class/output-context.d.ts.map +1 -0
- package/dist/remedy-class/output-context.js +150 -0
- package/dist/remedy-class/output-context.js.map +1 -0
- package/dist/remedy-class/sha256.d.ts +18 -0
- package/dist/remedy-class/sha256.d.ts.map +1 -0
- package/dist/remedy-class/sha256.js +89 -0
- package/dist/remedy-class/sha256.js.map +1 -0
- package/dist/remedy-class/table.d.ts +130 -0
- package/dist/remedy-class/table.d.ts.map +1 -0
- package/dist/remedy-class/table.js +457 -0
- package/dist/remedy-class/table.js.map +1 -0
- 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 +60 -5
- package/dist/resolution/cross-file.js.map +1 -1
- package/dist/stable-ids/builder.d.ts +20 -0
- package/dist/stable-ids/builder.d.ts.map +1 -0
- package/dist/stable-ids/builder.js +65 -0
- package/dist/stable-ids/builder.js.map +1 -0
- package/dist/stable-ids/diff.d.ts +18 -0
- package/dist/stable-ids/diff.d.ts.map +1 -0
- package/dist/stable-ids/diff.js +37 -0
- package/dist/stable-ids/diff.js.map +1 -0
- package/dist/stable-ids/go.d.ts +28 -0
- package/dist/stable-ids/go.d.ts.map +1 -0
- package/dist/stable-ids/go.js +160 -0
- package/dist/stable-ids/go.js.map +1 -0
- package/dist/stable-ids/hash.d.ts +22 -0
- package/dist/stable-ids/hash.d.ts.map +1 -0
- package/dist/stable-ids/hash.js +167 -0
- package/dist/stable-ids/hash.js.map +1 -0
- package/dist/stable-ids/index.d.ts +30 -0
- package/dist/stable-ids/index.d.ts.map +1 -0
- package/dist/stable-ids/index.js +59 -0
- package/dist/stable-ids/index.js.map +1 -0
- package/dist/stable-ids/java.d.ts +28 -0
- package/dist/stable-ids/java.d.ts.map +1 -0
- package/dist/stable-ids/java.js +224 -0
- package/dist/stable-ids/java.js.map +1 -0
- package/dist/stable-ids/moves.d.ts +87 -0
- package/dist/stable-ids/moves.d.ts.map +1 -0
- package/dist/stable-ids/moves.js +222 -0
- package/dist/stable-ids/moves.js.map +1 -0
- package/dist/stable-ids/nodes.d.ts +32 -0
- package/dist/stable-ids/nodes.d.ts.map +1 -0
- package/dist/stable-ids/nodes.js +92 -0
- package/dist/stable-ids/nodes.js.map +1 -0
- package/dist/stable-ids/normalize.d.ts +35 -0
- package/dist/stable-ids/normalize.d.ts.map +1 -0
- package/dist/stable-ids/normalize.js +174 -0
- package/dist/stable-ids/normalize.js.map +1 -0
- package/dist/stable-ids/parse-errors.d.ts +24 -0
- package/dist/stable-ids/parse-errors.d.ts.map +1 -0
- package/dist/stable-ids/parse-errors.js +46 -0
- package/dist/stable-ids/parse-errors.js.map +1 -0
- package/dist/stable-ids/python.d.ts +27 -0
- package/dist/stable-ids/python.d.ts.map +1 -0
- package/dist/stable-ids/python.js +212 -0
- package/dist/stable-ids/python.js.map +1 -0
- package/dist/stable-ids/ts-parse-errors.d.ts +27 -0
- package/dist/stable-ids/ts-parse-errors.d.ts.map +1 -0
- package/dist/stable-ids/ts-parse-errors.js +75 -0
- package/dist/stable-ids/ts-parse-errors.js.map +1 -0
- package/dist/stable-ids/types.d.ts +106 -0
- package/dist/stable-ids/types.d.ts.map +1 -0
- package/dist/stable-ids/types.js +16 -0
- package/dist/stable-ids/types.js.map +1 -0
- package/dist/stable-ids/typescript.d.ts +30 -0
- package/dist/stable-ids/typescript.d.ts.map +1 -0
- package/dist/stable-ids/typescript.js +362 -0
- package/dist/stable-ids/typescript.js.map +1 -0
- package/dist/types/config.d.ts +9 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/index.d.ts +35 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -20,6 +20,7 @@ import { walkBackwardDefs } from '../dfg-walk.js';
|
|
|
20
20
|
import { sanitizerCoversSink } from '../sanitizer-index.js';
|
|
21
21
|
import { HTML_CONTEXT_ENCODER_METHODS } from '../constant-propagation/patterns.js';
|
|
22
22
|
import { javaCanonicalStartsWithAllBare } from '../java-canonical-prefix.js';
|
|
23
|
+
import { shouldGateInterproceduralParam } from '../entry-point-detection.js';
|
|
23
24
|
/**
|
|
24
25
|
* cognium-dev#328 — the const-prop per-step veto, with two scoped exemptions.
|
|
25
26
|
*
|
|
@@ -438,6 +439,40 @@ function indexJavaLocalAssignments(code) {
|
|
|
438
439
|
}
|
|
439
440
|
return index;
|
|
440
441
|
}
|
|
442
|
+
function goCalleeBaseName(callee) {
|
|
443
|
+
const dot = callee.lastIndexOf('.');
|
|
444
|
+
return dot === -1 ? callee : callee.slice(dot + 1);
|
|
445
|
+
}
|
|
446
|
+
/** cognium-dev#783: callee from a Go `:=` or `var x =` assignment line (unqualified or dotted). */
|
|
447
|
+
function goConstantHelperCalleeOnLine(line) {
|
|
448
|
+
const m = line.match(/:=\s*([\w.]+)\s*\(/) ?? line.match(/\bvar\s+\w+\s*=\s*([\w.]+)\s*\(/);
|
|
449
|
+
if (!m)
|
|
450
|
+
return null;
|
|
451
|
+
return goCalleeBaseName(m[1]);
|
|
452
|
+
}
|
|
453
|
+
/** Same as {@link goConstantHelperCalleeOnLine} when the call spans the next lines after `:=` / `var`. */
|
|
454
|
+
function goConstantHelperCalleeFromLines(lines, lineNumber) {
|
|
455
|
+
const direct = goConstantHelperCalleeOnLine(lines[lineNumber - 1] ?? '');
|
|
456
|
+
if (direct)
|
|
457
|
+
return direct;
|
|
458
|
+
const cur = lines[lineNumber - 1] ?? '';
|
|
459
|
+
const partial = cur.match(/:=\s*([\w.]+)\s*$/) ?? cur.match(/\bvar\s+\w+\s*=\s*([\w.]+)\s*$/);
|
|
460
|
+
if (partial) {
|
|
461
|
+
const next = (lines[lineNumber] ?? '').trimStart();
|
|
462
|
+
if (next.startsWith('('))
|
|
463
|
+
return goCalleeBaseName(partial[1]);
|
|
464
|
+
}
|
|
465
|
+
if (!cur.includes(':=') && !/\bvar\s+\w+\s*=/.test(cur))
|
|
466
|
+
return null;
|
|
467
|
+
if (cur.includes('('))
|
|
468
|
+
return null;
|
|
469
|
+
for (let i = lineNumber + 1; i <= Math.min(lines.length, lineNumber + 4); i++) {
|
|
470
|
+
const m = (lines[i - 1] ?? '').match(/^\s*([\w.]+)\s*\(/);
|
|
471
|
+
if (m)
|
|
472
|
+
return goCalleeBaseName(m[1]);
|
|
473
|
+
}
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
441
476
|
function makeConstPropVeto(constProp, graph, sources, code, language, sanitizers) {
|
|
442
477
|
const lines = typeof code === 'string' ? code.split('\n') : [];
|
|
443
478
|
const selfReassign = new Map();
|
|
@@ -588,8 +623,8 @@ function makeConstPropVeto(constProp, graph, sources, code, language, sanitizers
|
|
|
588
623
|
if (step.line === sinkLine &&
|
|
589
624
|
!constProp.tainted.has(fpLookup)) {
|
|
590
625
|
for (let ln = sourceLine; ln <= sinkLine; ln++) {
|
|
591
|
-
const
|
|
592
|
-
if (
|
|
626
|
+
const callee = goConstantHelperCalleeFromLines(lines, ln);
|
|
627
|
+
if (callee && constProp.constantReturningMethods?.has(callee)) {
|
|
593
628
|
return true;
|
|
594
629
|
}
|
|
595
630
|
}
|
|
@@ -908,7 +943,7 @@ export class TaintPropagationPass {
|
|
|
908
943
|
}
|
|
909
944
|
// Supplement: direct parameter-to-sink flows
|
|
910
945
|
// Sprint 82 (#189) — sink-type-aware dedup (see arrayFlows comment).
|
|
911
|
-
const paramFlows = detectParameterSinkFlows(types, calls, sources, sinks, constProp.unreachableLines, constProp.tainted, ctx.code) ?? [];
|
|
946
|
+
const paramFlows = detectParameterSinkFlows(types, calls, sources, sinks, constProp.unreachableLines, constProp.tainted, ctx.code, ctx.language, graph.ir.meta.file) ?? [];
|
|
912
947
|
for (const f of paramFlows) {
|
|
913
948
|
pushIfNew(f);
|
|
914
949
|
}
|
|
@@ -1022,6 +1057,14 @@ export class TaintPropagationPass {
|
|
|
1022
1057
|
return false;
|
|
1023
1058
|
return true;
|
|
1024
1059
|
});
|
|
1060
|
+
if (ctx.language === 'csharp') {
|
|
1061
|
+
finalFlows = finalFlows.filter((f) => !shouldGateCSharpPatPermsLibraryParamFlow(f, sources, sinks, types, {
|
|
1062
|
+
language: ctx.language,
|
|
1063
|
+
types,
|
|
1064
|
+
filePath: graph.ir.meta.file,
|
|
1065
|
+
calls,
|
|
1066
|
+
}));
|
|
1067
|
+
}
|
|
1025
1068
|
// Sprint 24 (cognium-dev #102) — uniform line-keyed sanitizer
|
|
1026
1069
|
// suppression. Drop any flow whose sink_line carries a registered
|
|
1027
1070
|
// sanitizer that covers the flow's sink_type. Several supplementary
|
|
@@ -1713,7 +1756,7 @@ function detectJsModuleScopeFlows(code, sources, sinks, unreachableLines) {
|
|
|
1713
1756
|
const stripped = line.replace(/\s+$/, '');
|
|
1714
1757
|
if (!stripped || /^[ \t]/.test(line))
|
|
1715
1758
|
continue;
|
|
1716
|
-
const m = stripped.match(/^(?:let|var|const)\s+([A-Za-z_$][\w$]*)\b/);
|
|
1759
|
+
const m = stripped.match(/^(?:export\s+)?(?:let|var|const)\s+([A-Za-z_$][\w$]*)\b/);
|
|
1717
1760
|
if (m)
|
|
1718
1761
|
moduleVars.add(m[1]);
|
|
1719
1762
|
}
|
|
@@ -1732,7 +1775,7 @@ function detectJsModuleScopeFlows(code, sources, sinks, unreachableLines) {
|
|
|
1732
1775
|
if (unreachableLines.has(i + 1))
|
|
1733
1776
|
continue;
|
|
1734
1777
|
for (const lhs of moduleVars) {
|
|
1735
|
-
const declRe = new RegExp(`\\b(?:let|const|var)\\s+${lhs.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`);
|
|
1778
|
+
const declRe = new RegExp(`\\b(?:export\\s+)?(?:let|const|var)\\s+${lhs.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`);
|
|
1736
1779
|
if (declRe.test(line))
|
|
1737
1780
|
continue;
|
|
1738
1781
|
const m = line.match(new RegExp(`\\b${lhs.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*=\\s*([^;]+)`));
|
|
@@ -1901,6 +1944,18 @@ function isTaintedInMethod(taintedVars, varName, scopedName, fieldNames, isField
|
|
|
1901
1944
|
}
|
|
1902
1945
|
return true;
|
|
1903
1946
|
}
|
|
1947
|
+
function mapGetLiteralKeyFromExpr(expr) {
|
|
1948
|
+
const m = expr.match(/\b([A-Za-z_]\w*)\s*\.\s*get\s*\(\s*"([^"]*)"\s*\)/);
|
|
1949
|
+
return m ? { map: m[1], key: m[2] } : null;
|
|
1950
|
+
}
|
|
1951
|
+
function isMapLiteralKeyTainted(constProp, mapName, key, inMethod) {
|
|
1952
|
+
const scoped = inMethod ? `${inMethod}:${mapName}` : mapName;
|
|
1953
|
+
const keys = constProp.taintedCollections.get(mapName) ??
|
|
1954
|
+
constProp.taintedCollections.get(scoped);
|
|
1955
|
+
if (!keys || keys.size === 0)
|
|
1956
|
+
return false;
|
|
1957
|
+
return keys.has(key) || keys.has('*');
|
|
1958
|
+
}
|
|
1904
1959
|
function detectCollectionFlows(calls, sources, sinks, constProp, code, types, graph) {
|
|
1905
1960
|
const taintedVars = constProp.tainted;
|
|
1906
1961
|
const unreachableLines = constProp.unreachableLines;
|
|
@@ -1944,7 +1999,12 @@ function detectCollectionFlows(calls, sources, sinks, constProp, code, types, gr
|
|
|
1944
1999
|
&& expr === varName
|
|
1945
2000
|
&& !methodHasLocalDecl(code, call.in_method, varName, call.location.line);
|
|
1946
2001
|
const isFieldUse = explicitField || bareFieldRead;
|
|
1947
|
-
|
|
2002
|
+
const mapKeyRead = mapGetLiteralKeyFromExpr(expr);
|
|
2003
|
+
let argTainted = isTaintedInMethod(taintedVars, varName, scopedName, fieldNames, isFieldUse);
|
|
2004
|
+
if (mapKeyRead && mapKeyRead.map === varName) {
|
|
2005
|
+
argTainted = isMapLiteralKeyTainted(constProp, varName, mapKeyRead.key, call.in_method);
|
|
2006
|
+
}
|
|
2007
|
+
if (argTainted) {
|
|
1948
2008
|
// Sprint 13 #70 — pick a source in the same method scope as the
|
|
1949
2009
|
// sink, not blanket sources[0]. The varName-based match is
|
|
1950
2010
|
// primary; method-scope is the tiebreaker; sources[0] is the
|
|
@@ -1999,12 +2059,19 @@ function detectCollectionFlows(calls, sources, sinks, constProp, code, types, gr
|
|
|
1999
2059
|
{ method: 'peek', re: /(\w+)\.peek\(/ },
|
|
2000
2060
|
{ method: 'toArray', re: /(\w+)\.toArray\(/ },
|
|
2001
2061
|
];
|
|
2002
|
-
for (const { re } of collectionPatterns) {
|
|
2062
|
+
for (const { method, re } of collectionPatterns) {
|
|
2003
2063
|
const match = expr.match(re);
|
|
2004
2064
|
if (match) {
|
|
2005
2065
|
const collectionVar = match[1];
|
|
2006
2066
|
const scopedCollection = call.in_method ? `${call.in_method}:${collectionVar}` : collectionVar;
|
|
2007
|
-
|
|
2067
|
+
const mapKey = method === 'get' ? mapGetLiteralKeyFromExpr(expr) : null;
|
|
2068
|
+
let collectionTainted = taintedVars.has(collectionVar) || taintedVars.has(scopedCollection);
|
|
2069
|
+
if (mapKey && mapKey.map === collectionVar) {
|
|
2070
|
+
collectionTainted = isMapLiteralKeyTainted(constProp, collectionVar, mapKey.key, call.in_method);
|
|
2071
|
+
}
|
|
2072
|
+
if (!collectionTainted)
|
|
2073
|
+
continue;
|
|
2074
|
+
{
|
|
2008
2075
|
// Sprint 13 #70 — same method-scoped picker as above.
|
|
2009
2076
|
const source = pickScopedSource(sources, sink.line, call.in_method ?? null, types, collectionVar);
|
|
2010
2077
|
if (source) {
|
|
@@ -2090,6 +2157,40 @@ function detectArrayElementFlows(calls, sources, sinks, taintedArrayElements, un
|
|
|
2090
2157
|
}
|
|
2091
2158
|
return flows;
|
|
2092
2159
|
}
|
|
2160
|
+
/**
|
|
2161
|
+
* cognium-dev #816 — PAT-PERMS-01: suppress only direct library-parameter →
|
|
2162
|
+
* FileStream path_traversal on non-entry methods. Derived paths (Path.Combine,
|
|
2163
|
+
* GetFullPath chains) and other sinks stay gated only by sanitizer / DFG logic.
|
|
2164
|
+
*/
|
|
2165
|
+
function csharpPatPermsDirectParamSink(sink, paramVar) {
|
|
2166
|
+
const method = (sink.method ?? '').replace(/^.*\./, '');
|
|
2167
|
+
if (method !== 'FileStream')
|
|
2168
|
+
return false;
|
|
2169
|
+
const code = sink.code ?? '';
|
|
2170
|
+
if (!code)
|
|
2171
|
+
return true;
|
|
2172
|
+
const escaped = paramVar.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
2173
|
+
return new RegExp(`\\bFileStream\\s*\\(\\s*${escaped}\\b`).test(code);
|
|
2174
|
+
}
|
|
2175
|
+
function shouldGateCSharpPatPermsLibraryParamFlow(flow, sources, sinks, types, ctx) {
|
|
2176
|
+
if (flow.source_type !== 'interprocedural_param' || flow.sink_type !== 'path_traversal') {
|
|
2177
|
+
return false;
|
|
2178
|
+
}
|
|
2179
|
+
const srcVar = flow.path?.[0]?.variable;
|
|
2180
|
+
const sinkVar = flow.path?.[flow.path.length - 1]?.variable;
|
|
2181
|
+
if (!srcVar || srcVar !== sinkVar)
|
|
2182
|
+
return false;
|
|
2183
|
+
const sink = sinks.find((s) => s.line === flow.sink_line && s.type === 'path_traversal');
|
|
2184
|
+
if (!sink || !csharpPatPermsDirectParamSink(sink, srcVar))
|
|
2185
|
+
return false;
|
|
2186
|
+
const src = sources.find((s) => s.line === flow.source_line && s.type === 'interprocedural_param');
|
|
2187
|
+
const methodName = src?.in_method;
|
|
2188
|
+
if (!methodName)
|
|
2189
|
+
return false;
|
|
2190
|
+
const enclosingType = types.find((t) => t.methods.some((m) => m.name === methodName));
|
|
2191
|
+
const enclosingMethod = enclosingType?.methods.find((m) => m.name === methodName);
|
|
2192
|
+
return shouldGateInterproceduralParam(flow.source_type, enclosingMethod, enclosingType, ctx);
|
|
2193
|
+
}
|
|
2093
2194
|
/** Parameter names referenced as identifiers inside a compound sink argument (#685). */
|
|
2094
2195
|
function compoundArgParamNames(expression, paramNames) {
|
|
2095
2196
|
const stripped = expression.replace(/(['"`])(?:\\.|(?!\1).)*\1/g, (m) => ' '.repeat(m.length));
|
|
@@ -2104,7 +2205,7 @@ function compoundArgParamNames(expression, paramNames) {
|
|
|
2104
2205
|
}
|
|
2105
2206
|
return matched;
|
|
2106
2207
|
}
|
|
2107
|
-
function detectParameterSinkFlows(types, calls, sources, sinks, unreachableLines, tainted, code) {
|
|
2208
|
+
function detectParameterSinkFlows(types, calls, sources, sinks, unreachableLines, tainted, code, language, filePath) {
|
|
2108
2209
|
const flows = [];
|
|
2109
2210
|
const paramSourcesByMethod = new Map();
|
|
2110
2211
|
for (const source of sources) {
|
|
@@ -2154,6 +2255,16 @@ function detectParameterSinkFlows(types, calls, sources, sinks, unreachableLines
|
|
|
2154
2255
|
for (const varName of varNames) {
|
|
2155
2256
|
const paramSource = methodParamSources.get(varName);
|
|
2156
2257
|
if (paramSource) {
|
|
2258
|
+
if (language === 'csharp' &&
|
|
2259
|
+
paramSource.type === 'interprocedural_param' &&
|
|
2260
|
+
sink.type === 'path_traversal' &&
|
|
2261
|
+
csharpPatPermsDirectParamSink(sink, varName)) {
|
|
2262
|
+
const enclosingType = types.find((t) => t.methods.some((m) => m.name === methodName));
|
|
2263
|
+
const enclosingMethod = enclosingType?.methods.find((m) => m.name === methodName);
|
|
2264
|
+
if (shouldGateInterproceduralParam(paramSource.type, enclosingMethod, enclosingType, { language, types, filePath, calls })) {
|
|
2265
|
+
continue;
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2157
2268
|
// Sprint 82 (#189) — sink-type-aware dedup so a sink registered
|
|
2158
2269
|
// under multiple types at the same call site (e.g. `redirect` as
|
|
2159
2270
|
// both `open_redirect` and `crlf`) emits a flow for each type.
|
|
@@ -3660,10 +3771,22 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
3660
3771
|
realSourceByVar.set(s.variable, s);
|
|
3661
3772
|
}
|
|
3662
3773
|
for (const [varName, derivedLine] of derived) {
|
|
3663
|
-
if (!varName
|
|
3774
|
+
if (!varName)
|
|
3664
3775
|
continue;
|
|
3665
3776
|
const owner = methodAt(derivedLine);
|
|
3666
3777
|
const fieldAlias = isDeclaredField(derivedLine, varName);
|
|
3778
|
+
if (existingVars.has(varName)) {
|
|
3779
|
+
if (!fieldAlias)
|
|
3780
|
+
continue;
|
|
3781
|
+
// cognium-dev#626: a bean setter's `interprocedural_param` stub must not
|
|
3782
|
+
// block the declared-field alias derived from a tainted `setFoo(...)` /
|
|
3783
|
+
// `this.foo =` write — otherwise sinks in other methods never see `foo`.
|
|
3784
|
+
const stubIdx = sourcesWithVar.findIndex(s => s.variable === varName && s.type === 'interprocedural_param');
|
|
3785
|
+
if (stubIdx < 0)
|
|
3786
|
+
continue;
|
|
3787
|
+
sourcesWithVar.splice(stubIdx, 1);
|
|
3788
|
+
existingVars.delete(varName);
|
|
3789
|
+
}
|
|
3667
3790
|
let scopedAnchor = anchor;
|
|
3668
3791
|
if (owner) {
|
|
3669
3792
|
let best;
|