# Risk Engine FixChain Integration > **Sprint:** SPRINT_20260110_012_007_RISK > **Last Updated:** 10-Jan-2026 ## Overview The Risk Engine FixChain integration enables automatic risk score adjustment based on verified fix status from FixChain attestations. When a vulnerability has a verified fix, the risk score is reduced proportionally to the verification confidence level. ## Why This Matters | Current State | With FixChain Integration | |---------------|---------------------------| | Risk scores ignore fix verification | Fix confidence reduces risk | | Binary matches = always vulnerable | Verified fixes lower severity | | No credit for patched backports | Backport fixes recognized | | Manual risk exceptions needed | Automatic risk adjustment | ## Risk Adjustment Model ### Verdict to Risk Modifier Mapping | Verdict | Confidence | Risk Modifier | Rationale | |---------|------------|---------------|-----------| | `fixed` | >= 95% | -80% to -90% | High-confidence verified fix | | `fixed` | 85-95% | -60% to -80% | Verified fix, some uncertainty | | `fixed` | 70-85% | -40% to -60% | Likely fixed, needs confirmation | | `fixed` | 60-70% | -20% to -40% | Possible fix, low confidence | | `fixed` | < 60% | 0% | Below threshold, no adjustment | | `partial` | >= 60% | -25% to -50% | Partial fix applied | | `inconclusive` | any | 0% | Cannot determine, conservative | | `still_vulnerable` | any | 0% | No fix detected | | No attestation | N/A | 0% | No verification performed | ### Modifier Formula ``` AdjustedRisk = BaseRisk * (1 - (Modifier * ConfidenceWeight)) Where: Modifier = verdict-based modifier from table above ConfidenceWeight = min(1.0, (Confidence - MinThreshold) / (1.0 - MinThreshold)) ``` ### Example Calculation ``` CVE-2024-0727 on pkg:deb/debian/openssl@3.0.11-1~deb12u2: BaseRisk = 8.5 (HIGH) FixChain Verdict = "fixed" FixChain Confidence = 0.97 Modifier = 0.90 (high confidence tier) ConfidenceWeight = (0.97 - 0.60) / (1.0 - 0.60) = 0.925 AdjustedRisk = 8.5 * (1 - 0.90 * 0.925) = 8.5 * 0.1675 = 1.42 (LOW) ``` ## Components ### IFixChainRiskProvider Main interface for FixChain risk integration: ```csharp public interface IFixChainRiskProvider { Task GetFixStatusAsync( string cveId, string binarySha256, string? componentPurl = null, CancellationToken ct = default); double ComputeRiskAdjustment(FixVerificationStatus status); FixChainRiskFactor CreateRiskFactor(FixVerificationStatus status); } ``` ### FixChainRiskProvider Implementation that: 1. Queries the attestation store for FixChain predicates 2. Computes risk adjustment based on verdict and confidence 3. Creates structured risk factors for UI display ### IFixChainAttestationClient Client for querying attestations: ```csharp public interface IFixChainAttestationClient { Task GetFixChainAsync( string cveId, string binarySha256, string? componentPurl = null, CancellationToken ct = default); Task> GetForComponentAsync( string componentPurl, CancellationToken ct = default); } ``` ## Configuration ### YAML Configuration ```yaml RiskEngine: Providers: FixChain: Enabled: true HighConfidenceThreshold: 0.95 MediumConfidenceThreshold: 0.85 LowConfidenceThreshold: 0.70 MinConfidenceThreshold: 0.60 FixedReduction: 0.90 PartialReduction: 0.50 MaxRiskReduction: 0.90 CacheMaxAgeHours: 24 ``` ### Service Registration ```csharp services.AddOptions() .Bind(config.GetSection("RiskEngine:Providers:FixChain")) .ValidateDataAnnotations() .ValidateOnStart(); services.AddSingleton(); services.AddHttpClient(); ``` ## Usage ### Getting Fix Status ```csharp var provider = services.GetRequiredService(); var status = await provider.GetFixStatusAsync( "CVE-2024-0727", binarySha256, componentPurl); if (status is not null) { var adjustment = provider.ComputeRiskAdjustment(status); var adjustedRisk = baseRisk * adjustment; } ``` ### Creating Risk Factors ```csharp var status = await provider.GetFixStatusAsync(cveId, binarySha256); if (status is not null) { var factor = provider.CreateRiskFactor(status); // For UI display var display = factor.ToDisplay(); var badge = factor.ToBadge(); var summary = factor.ToSummary(); } ``` ### Signal-Based Scoring For batch processing via signals: ```csharp var signals = new Dictionary { [FixChainRiskProvider.SignalFixConfidence] = 0.95, [FixChainRiskProvider.SignalFixStatus] = FixChainRiskProvider.EncodeStatus("fixed") }; var request = new ScoreRequest("fixchain", subject, signals); var adjustment = await provider.ScoreAsync(request, ct); ``` ## Metrics The integration exposes the following OpenTelemetry metrics: | Metric | Type | Description | |--------|------|-------------| | `risk_fixchain_lookups_total` | Counter | Total attestation lookups | | `risk_fixchain_hits_total` | Counter | Attestations found | | `risk_fixchain_misses_total` | Counter | Lookups with no attestation | | `risk_fixchain_cache_hits_total` | Counter | Lookups served from cache | | `risk_fixchain_lookup_duration_seconds` | Histogram | Lookup duration | | `risk_fixchain_adjustments_total` | Counter | Risk adjustments applied | | `risk_fixchain_reduction_percent` | Histogram | Reduction percentage distribution | | `risk_fixchain_errors_total` | Counter | Lookup errors | ### Recording Metrics ```csharp // Automatically recorded by the provider, or manually: FixChainRiskMetrics.RecordLookup( found: true, fromCache: false, durationSeconds: 0.05, verdict: "fixed"); FixChainRiskMetrics.RecordAdjustment( verdict: FixChainVerdictStatus.Fixed, confidence: 0.95m, reductionPercent: 0.80); ``` ## UI Integration ### Display Model ```csharp var display = factor.ToDisplay(); // display.Label = "Fix Verification" // display.Value = "Fixed (95% confidence)" // display.Impact = -0.80 // display.ImpactDirection = "decrease" // display.EvidenceRef = "fixchain://sha256:..." // display.Details = { verdict, confidence, verified_at, ... } ``` ### Badge Component ```csharp var badge = factor.ToBadge(); // badge.Status = "Fixed" // badge.Color = "green" // badge.Icon = "check-circle" // badge.Confidence = 0.95m // badge.Tooltip = "Verified fix (95% confidence)" ``` ## Testing ### Unit Tests ```csharp [Fact] public async Task FixedVerdict_HighConfidence_ReturnsLowRisk() { var provider = new FixChainRiskProvider(options); var status = new FixVerificationStatus { Verdict = "fixed", Confidence = 0.97m, VerifiedAt = DateTimeOffset.UtcNow, AttestationDigest = "sha256:test" }; var adjustment = provider.ComputeRiskAdjustment(status); adjustment.Should().BeLessThan(0.3); } ``` ### Integration Tests ```csharp [Fact] public async Task FullWorkflow_FixedVerdict_ReducesRisk() { var attestationClient = new InMemoryFixChainAttestationClient(); attestationClient.AddAttestation(cveId, binarySha256, attestation); var provider = new FixChainRiskProvider(options, attestationClient, logger); var status = await provider.GetFixStatusAsync(cveId, binarySha256); status.Should().NotBeNull(); status!.Verdict.Should().Be("fixed"); } ``` ## Decisions and Trade-offs | Decision | Rationale | |----------|-----------| | Conservative thresholds | Start high, can lower based on accuracy data | | No automatic upgrade | Inconclusive doesn't increase risk | | Cache TTL 30 minutes | Balances freshness vs. performance | | Attestation required | No reduction without verifiable evidence | | Minimum confidence 60% | Below this, evidence is too weak for adjustment | ## Related Documentation - [FixChain Attestation Predicate](../attestor/fix-chain-predicate.md) - [Golden Set Schema](../binary-index/golden-set-schema.md) - [Risk Engine Architecture](./architecture.md)