/** * LibraryProfileSinkGatePass — cognium-dev #232 * LibraryProfileCwe22PathGatePass — cognium-dev #245 RC1 (belt-and-suspenders) * * Sink-side companion to `LibraryProfileSourceGatePass` (#236, * shipped 3.151.0). Under the `library/*` project profile, drops * sinks whose entire vulnerability class is off-topic for library * code — currently just `log_injection` (CWE-117). * * The second (companion) class `LibraryProfileCwe22PathGatePass` * runs post-`InterproceduralPass` and filters `graph.ir.taint.flows` * for CWE-22 (`path_traversal`) flows whose source shape is * speculative (`interprocedural_param` / `constructor_field`). * `LibraryProfileSourceGatePass` already drops those `SourceType`s * from `graph.ir.taint.sources` under `library/*`, but this * companion catches any residual flows synthesised downstream that * bypassed the source-list mutation (belt-and-suspenders). * Empirically 170/246 CWE-22 H+C findings on the Tier 2 10-repo * cohort carried an `interprocedural_param` source with empty * `source.code` (cognium-ai#189 §4). * * Motivation: * * `log_injection` requires a downstream log-viewer that interprets * attacker-controlled log content — the exploit ("log forging", * HTML/ANSI injection into a log renderer, log-based privilege * escalation) is exercised at the application-integration boundary, * not inside a library. A library that calls `Logger.info(x)` where * `x` originated from an HTTP parameter has not committed a defect: * the consuming application decides where those log records are * rendered and how their content is escaped. * * Empirically, `log_injection` was ~10% of H+C findings on the * Tier 2 8-repo library cohort (402 findings in the audit * summarised in cognium-ai#189 §1). The signal is systemically * noisy for library code and provides no actionable * application-security value. * * Where #236 dropped speculative `interprocedural_param` sources * (which removed the entire `external_taint_escape` Scenario-B * synthesis path), this pass drops the sinks themselves. `log_injection` * has real, non-speculative sources (`http_param`, `env_input`, * `db_input`, …) that flow into concrete sink calls (`Logger.info`, * `logging.info`, `console.log`, …); the source-side gate does not * remove them. The *sink class* is what is off-topic here. * * Pipeline slot: runs after `CliMainReflectionSuppressPass` (so * every sink-side categorisation / suppression pass fires first) * and before `TaintPropagationPass` (so no dropped sink ever * reaches the flow generators). * * Guardrails: * - Pass is a no-op when `graph.ir.meta.projectProfile` is absent, * `'unknown'`, or does not start with `library/`. Callers that do * not opt in to profile detection get the unmodified sink list. * - Only `log_injection` is eligible in 3.152.0. Every other * `SinkType` (`sql_injection`, `command_injection`, `xss`, * `path_traversal`, `deserialization`, …) is preserved * unconditionally. Extending the drop set is a deliberate * one-line change in `DROPPED_SINK_TYPES`. * - Guarded on `disabledPasses.has('library-profile-sink-gate')` * at the pipeline registration site. * * Scope note (Rust log macros): `LanguageSourcesPass` emits * `rule_id: 'log_injection'` findings directly for Rust log macros * (`info!`, `println!`, `eprintln!`, …). Those findings bypass the * sink pipeline entirely and therefore bypass this pass. Deferred * to a follow-up if the harness rerun shows material Rust * residuals; the Tier 2 8-repo cohort is Java-heavy. */ import type { AnalysisPass, PassContext } from '../../graph/analysis-pass.js'; import type { ProjectProfile, SinkType, SourceType } from '../../types/index.js'; export interface LibraryProfileSinkGateResult { /** * Resolved `ProjectProfile` observed on `graph.ir.meta.projectProfile` * at the time this pass ran. `undefined` when no profile was * supplied by the caller. */ profile: ProjectProfile | undefined; /** * Whether the profile matched the library-shape trigger and the * gate was applied. `false` for every non-library shape and for * `'unknown'` / absent profiles. */ applied: boolean; /** * Number of sinks removed from the authoritative sink list. Zero * when `applied === false`. */ dropped: number; /** * Breakdown of drops by `SinkType`. Empty object when * `applied === false`. */ droppedByType: Partial>; } export declare class LibraryProfileSinkGatePass implements AnalysisPass { readonly name = "library-profile-sink-gate"; readonly category: "security"; run(ctx: PassContext): LibraryProfileSinkGateResult; } export interface LibraryProfileCwe22PathGateResult { /** * Resolved `ProjectProfile` observed on `graph.ir.meta.projectProfile` * at the time this pass ran. `undefined` when no profile was * supplied by the caller. */ profile: ProjectProfile | undefined; /** * Whether the profile matched the library-shape trigger and the * gate was applied. `false` for every non-library shape and for * `'unknown'` / absent profiles. */ applied: boolean; /** * Number of CWE-22 flows removed from `graph.ir.taint.flows`. * Zero when `applied === false` or when no matching flow existed. */ dropped: number; /** * Breakdown of drops by speculative source shape. Empty object * when `applied === false` or when no drops fired. */ droppedBySourceType: Partial>; } export declare class LibraryProfileCwe22PathGatePass implements AnalysisPass { readonly name = "library-profile-cwe22-path-gate"; readonly category: "security"; run(ctx: PassContext): LibraryProfileCwe22PathGateResult; } //# sourceMappingURL=library-profile-sink-gate-pass.d.ts.map