circle-ir 3.152.0 → 3.154.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.
Files changed (34) hide show
  1. package/configs/sink-semantics.json +102 -0
  2. package/configs/sinks/command.yaml +0 -10
  3. package/configs/sinks/deserialization.yaml +54 -0
  4. package/configs/sinks/path.yaml +0 -94
  5. package/configs/sinks/sql.yaml +24 -24
  6. package/dist/analysis/config-loader.d.ts.map +1 -1
  7. package/dist/analysis/config-loader.js +24 -8
  8. package/dist/analysis/config-loader.js.map +1 -1
  9. package/dist/analysis/passes/library-profile-sink-gate-pass.d.ts +43 -1
  10. package/dist/analysis/passes/library-profile-sink-gate-pass.d.ts.map +1 -1
  11. package/dist/analysis/passes/library-profile-sink-gate-pass.js +75 -0
  12. package/dist/analysis/passes/library-profile-sink-gate-pass.js.map +1 -1
  13. package/dist/analysis/passes/library-profile-xss-gate-pass.d.ts +104 -0
  14. package/dist/analysis/passes/library-profile-xss-gate-pass.d.ts.map +1 -0
  15. package/dist/analysis/passes/library-profile-xss-gate-pass.js +196 -0
  16. package/dist/analysis/passes/library-profile-xss-gate-pass.js.map +1 -0
  17. package/dist/analysis/require-entry-path.d.ts +91 -0
  18. package/dist/analysis/require-entry-path.d.ts.map +1 -0
  19. package/dist/analysis/require-entry-path.js +387 -0
  20. package/dist/analysis/require-entry-path.js.map +1 -0
  21. package/dist/analysis/taint-matcher.d.ts.map +1 -1
  22. package/dist/analysis/taint-matcher.js +55 -1
  23. package/dist/analysis/taint-matcher.js.map +1 -1
  24. package/dist/analyzer.d.ts.map +1 -1
  25. package/dist/analyzer.js +37 -1
  26. package/dist/analyzer.js.map +1 -1
  27. package/dist/browser/circle-ir.js +437 -257
  28. package/dist/core/circle-ir-core.cjs +38 -9
  29. package/dist/core/circle-ir-core.js +38 -9
  30. package/dist/types/config.d.ts +11 -1
  31. package/dist/types/config.d.ts.map +1 -1
  32. package/dist/types/index.d.ts +25 -0
  33. package/dist/types/index.d.ts.map +1 -1
  34. package/package.json +1 -1
@@ -1,11 +1,24 @@
1
1
  /**
2
2
  * LibraryProfileSinkGatePass — cognium-dev #232
3
+ * LibraryProfileCwe22PathGatePass — cognium-dev #245 RC1 (belt-and-suspenders)
3
4
  *
4
5
  * Sink-side companion to `LibraryProfileSourceGatePass` (#236,
5
6
  * shipped 3.151.0). Under the `library/*` project profile, drops
6
7
  * sinks whose entire vulnerability class is off-topic for library
7
8
  * code — currently just `log_injection` (CWE-117).
8
9
  *
10
+ * The second (companion) class `LibraryProfileCwe22PathGatePass`
11
+ * runs post-`InterproceduralPass` and filters `graph.ir.taint.flows`
12
+ * for CWE-22 (`path_traversal`) flows whose source shape is
13
+ * speculative (`interprocedural_param` / `constructor_field`).
14
+ * `LibraryProfileSourceGatePass` already drops those `SourceType`s
15
+ * from `graph.ir.taint.sources` under `library/*`, but this
16
+ * companion catches any residual flows synthesised downstream that
17
+ * bypassed the source-list mutation (belt-and-suspenders).
18
+ * Empirically 170/246 CWE-22 H+C findings on the Tier 2 10-repo
19
+ * cohort carried an `interprocedural_param` source with empty
20
+ * `source.code` (cognium-ai#189 §4).
21
+ *
9
22
  * Motivation:
10
23
  *
11
24
  * `log_injection` requires a downstream log-viewer that interprets
@@ -56,7 +69,7 @@
56
69
  * residuals; the Tier 2 8-repo cohort is Java-heavy.
57
70
  */
58
71
  import type { AnalysisPass, PassContext } from '../../graph/analysis-pass.js';
59
- import type { ProjectProfile, SinkType } from '../../types/index.js';
72
+ import type { ProjectProfile, SinkType, SourceType } from '../../types/index.js';
60
73
  export interface LibraryProfileSinkGateResult {
61
74
  /**
62
75
  * Resolved `ProjectProfile` observed on `graph.ir.meta.projectProfile`
@@ -86,4 +99,33 @@ export declare class LibraryProfileSinkGatePass implements AnalysisPass<LibraryP
86
99
  readonly category: "security";
87
100
  run(ctx: PassContext): LibraryProfileSinkGateResult;
88
101
  }
102
+ export interface LibraryProfileCwe22PathGateResult {
103
+ /**
104
+ * Resolved `ProjectProfile` observed on `graph.ir.meta.projectProfile`
105
+ * at the time this pass ran. `undefined` when no profile was
106
+ * supplied by the caller.
107
+ */
108
+ profile: ProjectProfile | undefined;
109
+ /**
110
+ * Whether the profile matched the library-shape trigger and the
111
+ * gate was applied. `false` for every non-library shape and for
112
+ * `'unknown'` / absent profiles.
113
+ */
114
+ applied: boolean;
115
+ /**
116
+ * Number of CWE-22 flows removed from `graph.ir.taint.flows`.
117
+ * Zero when `applied === false` or when no matching flow existed.
118
+ */
119
+ dropped: number;
120
+ /**
121
+ * Breakdown of drops by speculative source shape. Empty object
122
+ * when `applied === false` or when no drops fired.
123
+ */
124
+ droppedBySourceType: Partial<Record<SourceType, number>>;
125
+ }
126
+ export declare class LibraryProfileCwe22PathGatePass implements AnalysisPass<LibraryProfileCwe22PathGateResult> {
127
+ readonly name = "library-profile-cwe22-path-gate";
128
+ readonly category: "security";
129
+ run(ctx: PassContext): LibraryProfileCwe22PathGateResult;
130
+ }
89
131
  //# sourceMappingURL=library-profile-sink-gate-pass.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"library-profile-sink-gate-pass.d.ts","sourceRoot":"","sources":["../../../src/analysis/passes/library-profile-sink-gate-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAa,MAAM,sBAAsB,CAAC;AAYhF,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,OAAO,EAAE,cAAc,GAAG,SAAS,CAAC;IACpC;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;CAClD;AAaD,qBAAa,0BACX,YAAW,YAAY,CAAC,4BAA4B,CAAC;IAErD,QAAQ,CAAC,IAAI,+BAA+B;IAC5C,QAAQ,CAAC,QAAQ,EAAG,UAAU,CAAU;IAExC,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,4BAA4B;CA0DpD"}
1
+ {"version":3,"file":"library-profile-sink-gate-pass.d.ts","sourceRoot":"","sources":["../../../src/analysis/passes/library-profile-sink-gate-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,UAAU,EAA4B,MAAM,sBAAsB,CAAC;AAY3G,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,OAAO,EAAE,cAAc,GAAG,SAAS,CAAC;IACpC;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;CAClD;AAaD,qBAAa,0BACX,YAAW,YAAY,CAAC,4BAA4B,CAAC;IAErD,QAAQ,CAAC,IAAI,+BAA+B;IAC5C,QAAQ,CAAC,QAAQ,EAAG,UAAU,CAAU;IAExC,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,4BAA4B;CA0DpD;AAcD,MAAM,WAAW,iCAAiC;IAChD;;;;OAIG;IACH,OAAO,EAAE,cAAc,GAAG,SAAS,CAAC;IACpC;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,mBAAmB,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;CAC1D;AAED,qBAAa,+BACX,YAAW,YAAY,CAAC,iCAAiC,CAAC;IAE1D,QAAQ,CAAC,IAAI,qCAAqC;IAClD,QAAQ,CAAC,QAAQ,EAAG,UAAU,CAAU;IAExC,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,iCAAiC;CAuDzD"}
@@ -1,11 +1,24 @@
1
1
  /**
2
2
  * LibraryProfileSinkGatePass — cognium-dev #232
3
+ * LibraryProfileCwe22PathGatePass — cognium-dev #245 RC1 (belt-and-suspenders)
3
4
  *
4
5
  * Sink-side companion to `LibraryProfileSourceGatePass` (#236,
5
6
  * shipped 3.151.0). Under the `library/*` project profile, drops
6
7
  * sinks whose entire vulnerability class is off-topic for library
7
8
  * code — currently just `log_injection` (CWE-117).
8
9
  *
10
+ * The second (companion) class `LibraryProfileCwe22PathGatePass`
11
+ * runs post-`InterproceduralPass` and filters `graph.ir.taint.flows`
12
+ * for CWE-22 (`path_traversal`) flows whose source shape is
13
+ * speculative (`interprocedural_param` / `constructor_field`).
14
+ * `LibraryProfileSourceGatePass` already drops those `SourceType`s
15
+ * from `graph.ir.taint.sources` under `library/*`, but this
16
+ * companion catches any residual flows synthesised downstream that
17
+ * bypassed the source-list mutation (belt-and-suspenders).
18
+ * Empirically 170/246 CWE-22 H+C findings on the Tier 2 10-repo
19
+ * cohort carried an `interprocedural_param` source with empty
20
+ * `source.code` (cognium-ai#189 §4).
21
+ *
9
22
  * Motivation:
10
23
  *
11
24
  * `log_injection` requires a downstream log-viewer that interprets
@@ -129,4 +142,66 @@ export class LibraryProfileSinkGatePass {
129
142
  };
130
143
  }
131
144
  }
145
+ /**
146
+ * `SourceType`s eligible for the CWE-22 belt-and-suspenders drop.
147
+ * These are the same speculative shapes that `LibraryProfileSourceGatePass`
148
+ * drops from `graph.ir.taint.sources` under `library/*`. Listed
149
+ * here so the post-flow companion catches any flow that made it
150
+ * past the source-list mutation.
151
+ */
152
+ const CWE22_SPECULATIVE_SOURCE_TYPES = new Set([
153
+ 'interprocedural_param',
154
+ 'constructor_field',
155
+ ]);
156
+ export class LibraryProfileCwe22PathGatePass {
157
+ name = 'library-profile-cwe22-path-gate';
158
+ category = 'security';
159
+ run(ctx) {
160
+ const { graph } = ctx;
161
+ const profile = graph.ir.meta.projectProfile;
162
+ if (!isLibraryShape(profile)) {
163
+ return {
164
+ profile,
165
+ applied: false,
166
+ dropped: 0,
167
+ droppedBySourceType: {},
168
+ };
169
+ }
170
+ // `TaintPropagationPass` / `InterproceduralPass` populate
171
+ // `graph.ir.taint.flows`. Nothing to filter if no flow ever ran.
172
+ const flows = graph.ir.taint.flows;
173
+ if (!flows || flows.length === 0) {
174
+ return {
175
+ profile,
176
+ applied: true,
177
+ dropped: 0,
178
+ droppedBySourceType: {},
179
+ };
180
+ }
181
+ const droppedBySourceType = {};
182
+ const kept = [];
183
+ for (const flow of flows) {
184
+ if (flow.sink_type === 'path_traversal' &&
185
+ CWE22_SPECULATIVE_SOURCE_TYPES.has(flow.source_type)) {
186
+ droppedBySourceType[flow.source_type] =
187
+ (droppedBySourceType[flow.source_type] ?? 0) + 1;
188
+ continue;
189
+ }
190
+ kept.push(flow);
191
+ }
192
+ const dropped = flows.length - kept.length;
193
+ // Mutate the flow array in place so downstream consumers
194
+ // (`CrossFilePass`, SARIF writer) see the filtered list.
195
+ if (dropped > 0) {
196
+ flows.length = 0;
197
+ flows.push(...kept);
198
+ }
199
+ return {
200
+ profile,
201
+ applied: true,
202
+ dropped,
203
+ droppedBySourceType,
204
+ };
205
+ }
206
+ }
132
207
  //# sourceMappingURL=library-profile-sink-gate-pass.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"library-profile-sink-gate-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/library-profile-sink-gate-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAMH;;;;GAIG;AACH,MAAM,kBAAkB,GAA0B,IAAI,GAAG,CAAW;IAClE,eAAe;CAChB,CAAC,CAAC;AA2BH;;;;;GAKG;AACH,SAAS,cAAc,CAAC,OAAmC;IACzD,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACpD,OAAO,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,OAAO,0BAA0B;IAG5B,IAAI,GAAG,2BAA2B,CAAC;IACnC,QAAQ,GAAG,UAAmB,CAAC;IAExC,GAAG,CAAC,GAAgB;QAClB,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC;QACtB,MAAM,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC;QAE7C,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,OAAO;gBACL,OAAO;gBACP,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,CAAC;gBACV,aAAa,EAAE,EAAE;aAClB,CAAC;QACJ,CAAC;QAED,uDAAuD;QACvD,6DAA6D;QAC7D,8DAA8D;QAC9D,4DAA4D;QAC5D,mCAAmC;QACnC,MAAM,KAAK,GAAgB,GAAG,CAAC,SAAS,CAAC,aAAa,CAAC;YACrD,CAAC,CAAC,GAAG,CAAC,SAAS,CAAmB,aAAa,CAAC,CAAC,KAAK;YACtD,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC;QAEzB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO;gBACL,OAAO;gBACP,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,CAAC;gBACV,aAAa,EAAE,EAAE;aAClB,CAAC;QACJ,CAAC;QAED,MAAM,aAAa,GAAsC,EAAE,CAAC;QAC5D,MAAM,IAAI,GAAgB,EAAE,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;gBAC/D,SAAS;YACX,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAE3C,yDAAyD;QACzD,gEAAgE;QAChE,6CAA6C;QAC7C,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;YACjB,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QACtB,CAAC;QAED,OAAO;YACL,OAAO;YACP,OAAO,EAAE,IAAI;YACb,OAAO;YACP,aAAa;SACd,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"library-profile-sink-gate-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/library-profile-sink-gate-pass.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * LibraryProfileXssGatePass — cognium-dev #244
3
+ *
4
+ * Sink-side companion to `LibraryProfileSinkGatePass` (#232, canonical
5
+ * #112, shipped 3.152.0). Where #112 drops entire `SinkType`s under
6
+ * `library/*` (currently `log_injection`), this pass narrows the
7
+ * `xss` `SinkType` on a per-receiver-class basis: `TaintSink`s whose
8
+ * simple-name receiver class is in `XSS_NON_HTML_OUTPUT_CLASSES` are
9
+ * dropped before flow generation.
10
+ *
11
+ * Motivation:
12
+ *
13
+ * The current `xss` sink class treats any `String`-valued method
14
+ * receiver as a potential CWE-79 sink. Under `library/*` this
15
+ * over-collects by ~100x. A 10-repo Tier 2 library-profile audit
16
+ * (cognium-ai#189 §3, 2026-07) surfaced 507 H+C findings across
17
+ * hutool, xdocreport, languagetool, AndroidAsync, Sentinel,
18
+ * mybatis-plus, flyingsaucer, jedis — **zero** of which are actual
19
+ * HTML-output sinks. The 507 decompose as:
20
+ *
21
+ * - 149 (29.4%) `StringBuilder.append` / `StringBuffer.append` —
22
+ * in-memory buffers, not HTML output.
23
+ * - 66 (13.0%) `PrintStream.println` on `System.out` / `System.err` —
24
+ * CLI stdio, not HTML output.
25
+ * - 43 ( 8.5%) `response.body()` on `HttpRequest` / `HttpResponse` —
26
+ * outbound HTTP client body READ — a taint SOURCE, not sink.
27
+ * - 27 ( 5.3%) `response.end()` header terminator (AndroidAsync).
28
+ * - 26 ( 5.1%) `HttpSession.setAttribute` — session store IO.
29
+ * - 33 ( 6.5%) `write` on jedis wire-protocol writers.
30
+ * - 91 (17.9%) other (Loggers, JSON parsers, Netflix Zuul
31
+ * `RequestContext`, Sentinel `Context`).
32
+ *
33
+ * All eight buckets are `library/*` internal buffer / IO / logger /
34
+ * HTTP-client / router / JSON-parser plumbing. No web-app response
35
+ * writes reach `HttpServletResponse.getWriter().println(taint)` or
36
+ * a template renderer.
37
+ *
38
+ * Where #112 targets the whole vulnerability class (`log_injection`
39
+ * is off-topic for every library), CWE-79 is legitimate for library
40
+ * code that writes HTML (Thymeleaf, FreeMarker, Velocity, JSP
41
+ * fragments); it is only the RECEIVER SHAPE that is off-topic.
42
+ * Hence a class-level allowlist would over-drop and a class-level
43
+ * denylist is the calibrated response.
44
+ *
45
+ * Pipeline slot: runs immediately after `LibraryProfileSinkGatePass`
46
+ * (#112) and before `TaintPropagationPass` (so no dropped sink ever
47
+ * reaches the flow generators). Ordering ensures both library-profile
48
+ * gates fire under the same predicate before flow synthesis.
49
+ *
50
+ * Guardrails:
51
+ * - Pass is a no-op when `graph.ir.meta.projectProfile` is absent,
52
+ * `'unknown'`, or does not start with `library/`. Callers that do
53
+ * not opt in to profile detection get the unmodified sink list.
54
+ * - Only `xss`-type sinks are eligible; every other `SinkType`
55
+ * (`sql_injection`, `command_injection`, `path_traversal`,
56
+ * `deserialization`, …) is preserved unconditionally.
57
+ * - The class denylist is intentionally conservative: it only
58
+ * targets classes measured with zero HTML-output flows across the
59
+ * 10-repo cohort. `HttpServletResponse`, `JspWriter`,
60
+ * `ServletOutputStream`, `PrintWriter` (in servlet context),
61
+ * template engines (Thymeleaf `SpringWebContext`, FreeMarker
62
+ * `Environment`, Velocity `VelocityContext`) are **not** on the
63
+ * denylist and continue to fire.
64
+ * - Guarded on `disabledPasses.has('library-profile-xss-gate')` at
65
+ * the pipeline registration site.
66
+ *
67
+ * Reference:
68
+ * - cognium-dev#244 — this ticket.
69
+ * - cognium-dev#232 (#112, 3.152.0) — sink-side profile gate template.
70
+ * - cognium-ai#189 §3 — Tier 2 library-profile CWE-79 audit.
71
+ * - `docs/ARCHITECTURE.md` ADR-011.
72
+ */
73
+ import type { AnalysisPass, PassContext } from '../../graph/analysis-pass.js';
74
+ import type { ProjectProfile } from '../../types/index.js';
75
+ export interface LibraryProfileXssGateResult {
76
+ /**
77
+ * Resolved `ProjectProfile` observed on `graph.ir.meta.projectProfile`
78
+ * at the time this pass ran. `undefined` when no profile was
79
+ * supplied by the caller.
80
+ */
81
+ profile: ProjectProfile | undefined;
82
+ /**
83
+ * Whether the profile matched the library-shape trigger and the
84
+ * gate was applied. `false` for every non-library shape and for
85
+ * `'unknown'` / absent profiles.
86
+ */
87
+ applied: boolean;
88
+ /**
89
+ * Number of `xss` sinks removed from the authoritative sink list.
90
+ * Zero when `applied === false`.
91
+ */
92
+ dropped: number;
93
+ /**
94
+ * Breakdown of drops by receiver class (simple name). Empty object
95
+ * when `applied === false` or when no drops fired.
96
+ */
97
+ droppedByClass: Record<string, number>;
98
+ }
99
+ export declare class LibraryProfileXssGatePass implements AnalysisPass<LibraryProfileXssGateResult> {
100
+ readonly name = "library-profile-xss-gate";
101
+ readonly category: "security";
102
+ run(ctx: PassContext): LibraryProfileXssGateResult;
103
+ }
104
+ //# sourceMappingURL=library-profile-xss-gate-pass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"library-profile-xss-gate-pass.d.ts","sourceRoot":"","sources":["../../../src/analysis/passes/library-profile-xss-gate-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAa,MAAM,sBAAsB,CAAC;AA6DtE,MAAM,WAAW,2BAA2B;IAC1C;;;;OAIG;IACH,OAAO,EAAE,cAAc,GAAG,SAAS,CAAC;IACpC;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAaD,qBAAa,yBACX,YAAW,YAAY,CAAC,2BAA2B,CAAC;IAEpD,QAAQ,CAAC,IAAI,8BAA8B;IAC3C,QAAQ,CAAC,QAAQ,EAAG,UAAU,CAAU;IAExC,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,2BAA2B;CA0DnD"}
@@ -0,0 +1,196 @@
1
+ /**
2
+ * LibraryProfileXssGatePass — cognium-dev #244
3
+ *
4
+ * Sink-side companion to `LibraryProfileSinkGatePass` (#232, canonical
5
+ * #112, shipped 3.152.0). Where #112 drops entire `SinkType`s under
6
+ * `library/*` (currently `log_injection`), this pass narrows the
7
+ * `xss` `SinkType` on a per-receiver-class basis: `TaintSink`s whose
8
+ * simple-name receiver class is in `XSS_NON_HTML_OUTPUT_CLASSES` are
9
+ * dropped before flow generation.
10
+ *
11
+ * Motivation:
12
+ *
13
+ * The current `xss` sink class treats any `String`-valued method
14
+ * receiver as a potential CWE-79 sink. Under `library/*` this
15
+ * over-collects by ~100x. A 10-repo Tier 2 library-profile audit
16
+ * (cognium-ai#189 §3, 2026-07) surfaced 507 H+C findings across
17
+ * hutool, xdocreport, languagetool, AndroidAsync, Sentinel,
18
+ * mybatis-plus, flyingsaucer, jedis — **zero** of which are actual
19
+ * HTML-output sinks. The 507 decompose as:
20
+ *
21
+ * - 149 (29.4%) `StringBuilder.append` / `StringBuffer.append` —
22
+ * in-memory buffers, not HTML output.
23
+ * - 66 (13.0%) `PrintStream.println` on `System.out` / `System.err` —
24
+ * CLI stdio, not HTML output.
25
+ * - 43 ( 8.5%) `response.body()` on `HttpRequest` / `HttpResponse` —
26
+ * outbound HTTP client body READ — a taint SOURCE, not sink.
27
+ * - 27 ( 5.3%) `response.end()` header terminator (AndroidAsync).
28
+ * - 26 ( 5.1%) `HttpSession.setAttribute` — session store IO.
29
+ * - 33 ( 6.5%) `write` on jedis wire-protocol writers.
30
+ * - 91 (17.9%) other (Loggers, JSON parsers, Netflix Zuul
31
+ * `RequestContext`, Sentinel `Context`).
32
+ *
33
+ * All eight buckets are `library/*` internal buffer / IO / logger /
34
+ * HTTP-client / router / JSON-parser plumbing. No web-app response
35
+ * writes reach `HttpServletResponse.getWriter().println(taint)` or
36
+ * a template renderer.
37
+ *
38
+ * Where #112 targets the whole vulnerability class (`log_injection`
39
+ * is off-topic for every library), CWE-79 is legitimate for library
40
+ * code that writes HTML (Thymeleaf, FreeMarker, Velocity, JSP
41
+ * fragments); it is only the RECEIVER SHAPE that is off-topic.
42
+ * Hence a class-level allowlist would over-drop and a class-level
43
+ * denylist is the calibrated response.
44
+ *
45
+ * Pipeline slot: runs immediately after `LibraryProfileSinkGatePass`
46
+ * (#112) and before `TaintPropagationPass` (so no dropped sink ever
47
+ * reaches the flow generators). Ordering ensures both library-profile
48
+ * gates fire under the same predicate before flow synthesis.
49
+ *
50
+ * Guardrails:
51
+ * - Pass is a no-op when `graph.ir.meta.projectProfile` is absent,
52
+ * `'unknown'`, or does not start with `library/`. Callers that do
53
+ * not opt in to profile detection get the unmodified sink list.
54
+ * - Only `xss`-type sinks are eligible; every other `SinkType`
55
+ * (`sql_injection`, `command_injection`, `path_traversal`,
56
+ * `deserialization`, …) is preserved unconditionally.
57
+ * - The class denylist is intentionally conservative: it only
58
+ * targets classes measured with zero HTML-output flows across the
59
+ * 10-repo cohort. `HttpServletResponse`, `JspWriter`,
60
+ * `ServletOutputStream`, `PrintWriter` (in servlet context),
61
+ * template engines (Thymeleaf `SpringWebContext`, FreeMarker
62
+ * `Environment`, Velocity `VelocityContext`) are **not** on the
63
+ * denylist and continue to fire.
64
+ * - Guarded on `disabledPasses.has('library-profile-xss-gate')` at
65
+ * the pipeline registration site.
66
+ *
67
+ * Reference:
68
+ * - cognium-dev#244 — this ticket.
69
+ * - cognium-dev#232 (#112, 3.152.0) — sink-side profile gate template.
70
+ * - cognium-ai#189 §3 — Tier 2 library-profile CWE-79 audit.
71
+ * - `docs/ARCHITECTURE.md` ADR-011.
72
+ */
73
+ /**
74
+ * Simple-name receiver classes for which `xss` sinks are dropped
75
+ * under `library/*` profile. Each entry was measured with zero
76
+ * true-positive HTML-output flows across the 10-repo Tier 2 cohort
77
+ * (cognium-ai#189 §3, 2026-07).
78
+ *
79
+ * Extending this set is a deliberate, reviewable change. Adding an
80
+ * entry risks false-negative regressions on the OWASP Benchmark
81
+ * Java, SecuriBench Micro, and Juliet CWE-79 recall guards.
82
+ */
83
+ const XSS_NON_HTML_OUTPUT_CLASSES = new Set([
84
+ // In-memory buffers — no HTML output surface.
85
+ 'StringBuilder',
86
+ 'StringBuffer',
87
+ 'CharArrayWriter',
88
+ 'ByteArrayOutputStream',
89
+ // CLI stdio — CLI apps, not web response bodies.
90
+ 'PrintStream',
91
+ 'System',
92
+ // HTTP client builders — these are taint SOURCES (outbound reads),
93
+ // not XSS sinks. `response.body()`, `.post()`, `.get()` on
94
+ // hutool `HttpRequest` / `HttpResponse` reach us as sink
95
+ // matches only because xss.yaml catches String-valued receivers.
96
+ 'HttpRequest',
97
+ 'HttpRequestBuilder',
98
+ 'HttpResponse',
99
+ // Servlet non-body IO. `HttpSession.setAttribute`, `HttpSession.putValue`,
100
+ // `HttpServletRequest.setAttribute` are session/request attribute
101
+ // IO, not HTML output. Under `library/*` there is no JSP renderer
102
+ // reflecting them back. `HttpServletResponse` itself is NOT on
103
+ // this list — its writers are genuine XSS sinks.
104
+ 'HttpSession',
105
+ 'ServletRequest',
106
+ 'HttpServletRequest',
107
+ // Wire-protocol writers (jedis internal).
108
+ 'RedisOutputStream',
109
+ 'SafeEncoder',
110
+ 'RESP2',
111
+ 'Protocol',
112
+ // JSON parsers — these read JSON into POJOs. Source, not sink.
113
+ 'JSONUtil',
114
+ 'JSON',
115
+ 'ObjectMapper',
116
+ 'JsonReader',
117
+ // Loggers — log injection is CWE-117 (already covered by #112);
118
+ // these appear here because xss.yaml has a String-valued catch-all
119
+ // that hits Logger receivers.
120
+ 'Logger',
121
+ 'LoggerFactory',
122
+ 'Log',
123
+ 'Slf4jLogger',
124
+ // Router / interceptor context stores. Zuul `RequestContext`,
125
+ // Sentinel `Context` are internal request-processing state, not
126
+ // HTML output.
127
+ 'RequestContext',
128
+ 'Context',
129
+ ]);
130
+ /**
131
+ * Returns true when the resolved profile begins with `library/`
132
+ * (i.e. any `library/production`, `library/dev`, `library/sample`,
133
+ * `library/benchmark`, `library/test` environment binding).
134
+ * `'unknown'` and non-library shapes return false.
135
+ */
136
+ function isLibraryShape(profile) {
137
+ if (!profile || profile === 'unknown')
138
+ return false;
139
+ return profile.startsWith('library/');
140
+ }
141
+ export class LibraryProfileXssGatePass {
142
+ name = 'library-profile-xss-gate';
143
+ category = 'security';
144
+ run(ctx) {
145
+ const { graph } = ctx;
146
+ const profile = graph.ir.meta.projectProfile;
147
+ if (!isLibraryShape(profile)) {
148
+ return {
149
+ profile,
150
+ applied: false,
151
+ dropped: 0,
152
+ droppedByClass: {},
153
+ };
154
+ }
155
+ // Authoritative sink list mirrors the fetch pattern in
156
+ // `LibraryProfileSinkGatePass` and `SinkSemanticsPass`: prefer
157
+ // `SinkFilterResult.sinks` (what `analyzer.ts` assembles the
158
+ // final `taint.sinks` from), fall back to `graph.ir.taint.sinks`
159
+ // for stand-alone unit tests that don't run `SinkFilterPass`.
160
+ const sinks = ctx.hasResult('sink-filter')
161
+ ? ctx.getResult('sink-filter').sinks
162
+ : graph.ir.taint.sinks;
163
+ if (sinks.length === 0) {
164
+ return {
165
+ profile,
166
+ applied: true,
167
+ dropped: 0,
168
+ droppedByClass: {},
169
+ };
170
+ }
171
+ const droppedByClass = {};
172
+ const kept = [];
173
+ for (const sink of sinks) {
174
+ if (sink.type === 'xss' && sink.class && XSS_NON_HTML_OUTPUT_CLASSES.has(sink.class)) {
175
+ droppedByClass[sink.class] = (droppedByClass[sink.class] ?? 0) + 1;
176
+ continue;
177
+ }
178
+ kept.push(sink);
179
+ }
180
+ const dropped = sinks.length - kept.length;
181
+ // Mutate the array in place so downstream passes see the
182
+ // filtered list. Preserves array identity for any consumer that
183
+ // captured a reference before this pass ran.
184
+ if (dropped > 0) {
185
+ sinks.length = 0;
186
+ sinks.push(...kept);
187
+ }
188
+ return {
189
+ profile,
190
+ applied: true,
191
+ dropped,
192
+ droppedByClass,
193
+ };
194
+ }
195
+ }
196
+ //# sourceMappingURL=library-profile-xss-gate-pass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"library-profile-xss-gate-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/library-profile-xss-gate-pass.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Require-entry-path anchor (cognium-dev#234, ships 3.153.0).
3
+ *
4
+ * Post-pipeline, project-level helper that:
5
+ * 1. Annotates high+critical (H+C) taint findings with an
6
+ * `entryPath[]` chain of methods traversed from a classified
7
+ * Tier-1 entry point (Spring MVC handler, JAX-RS resource,
8
+ * Servlet lifecycle method, Netty channel handler, `main(String[])`,
9
+ * …) down to the finding's sink method.
10
+ * 2. Drops H+C findings under `application` / `server` / `cli` /
11
+ * `plugin` / `unknown` project profiles when the reverse-BFS
12
+ * conclusively returns no such chain — i.e. the finding lives on a
13
+ * method that no HTTP / RPC / lifecycle entry point in the scan can
14
+ * reach.
15
+ *
16
+ * # Why
17
+ *
18
+ * cognium-ai#189 §1 (2026-07 Tier-2 Java cohort — hutool, Sentinel,
19
+ * plantuml, mockserver) surfaced 1942 H+C findings on hutool with
20
+ * *zero* classified HTTP/RPC entry point and no reachable path from
21
+ * `main`. #236 (source-side profile gate, 3.151.0) and #232
22
+ * (sink-side profile gate, 3.152.0) each attacked the problem via
23
+ * profile-conditional per-file drops, but both leave the residual
24
+ * signal on files whose profile is `application/*` or `unknown` even
25
+ * though the enclosing method is manifestly unreachable from any
26
+ * classified boundary.
27
+ *
28
+ * This helper closes that hole: no entry point → no path from an
29
+ * entry point → no H+C finding. Every remaining H+C finding under
30
+ * `application/*` carries a demonstrable call chain from a real
31
+ * boundary as evidence, materialised on `entryPath[]` for consumers
32
+ * (CLI, SARIF, cognium-ai) to display.
33
+ *
34
+ * # Scope
35
+ *
36
+ * - Java only (relies on `classifyEntryPointTier`, which is Java-primary).
37
+ * Non-Java files: pass-through, no annotation, no drop.
38
+ * - Project-level only. Per-file `analyze()` never runs this helper —
39
+ * the reachability question is meaningful only across a full scan.
40
+ * - Only H+C findings from taint passes are candidates for drop. Metric
41
+ * findings, `medium` / `low` taint findings, and findings without a
42
+ * resolved containing method are always preserved.
43
+ *
44
+ * # Interaction with #236 / #232
45
+ *
46
+ * Both #236 and #232 fire when `projectProfile` starts with `library/`:
47
+ * the source / sink is dropped BEFORE the flow is materialised. This
48
+ * helper therefore no-ops under `library/*` (an already-dropped flow
49
+ * never reaches us) but still ANNOTATES findings with `entryPath[]`
50
+ * whenever a chain is available, so downstream consumers can see the
51
+ * anchor regardless of the drop decision.
52
+ *
53
+ * # Reference
54
+ *
55
+ * - cognium-dev#234 — this ticket.
56
+ * - cognium-dev#128 — entry-point tier classifier.
57
+ * - cognium-dev#236 (3.151.0) — source-side library-profile gate.
58
+ * - cognium-dev#232 (3.152.0) — sink-side library-profile gate.
59
+ * - cognium-ai#189 — Tier-2 Java cohort audit.
60
+ * - `docs/ARCHITECTURE.md` ADR-010.
61
+ */
62
+ import type { CircleIR, ProjectProfile } from '../types/index.js';
63
+ /** Rule identifier used for `disabledPasses` lookups. */
64
+ export declare const RULE_ID_REQUIRE_ENTRY_PATH = "require-entry-path";
65
+ export interface ApplyRequireEntryPathOptions {
66
+ /**
67
+ * Caller-resolved profile for each file. Same semantics as
68
+ * `AnalyzerOptions.projectProfile`. When absent, the helper treats
69
+ * every file as `'unknown'` — i.e. drops still apply.
70
+ */
71
+ projectProfile?: ProjectProfile | Map<string, ProjectProfile>;
72
+ /**
73
+ * Set of disabled pass ids (from `AnalyzerOptions.disabledPasses`).
74
+ * If it contains `'require-entry-path'`, the helper is a full no-op
75
+ * (no annotation, no drop).
76
+ */
77
+ disabledPasses?: ReadonlySet<string> | ReadonlyArray<string>;
78
+ }
79
+ /**
80
+ * Apply the entry-path gate + annotation to every file's findings in
81
+ * `fileAnalyses`, mutating each `analysis.findings` array in place.
82
+ *
83
+ * The mutation is idempotent — running twice produces the same result
84
+ * (BFS is deterministic; annotation always overwrites prior fields
85
+ * with the same values).
86
+ */
87
+ export declare function applyRequireEntryPath(fileAnalyses: ReadonlyArray<{
88
+ file: string;
89
+ analysis: CircleIR;
90
+ }>, options?: ApplyRequireEntryPathOptions): void;
91
+ //# sourceMappingURL=require-entry-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-entry-path.d.ts","sourceRoot":"","sources":["../../src/analysis/require-entry-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AAEH,OAAO,KAAK,EACV,QAAQ,EAER,cAAc,EAIf,MAAM,mBAAmB,CAAC;AAO3B,yDAAyD;AACzD,eAAO,MAAM,0BAA0B,uBAAuB,CAAC;AAe/D,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,cAAc,CAAC,EAAE,cAAc,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC9D;;;;OAIG;IACH,cAAc,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;CAC9D;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,EACjE,OAAO,GAAE,4BAAiC,GACzC,IAAI,CA6CN"}