- Introduced `sink-detect.js` with various security sink detection patterns categorized by type (e.g., command injection, SQL injection, file operations). - Implemented functions to build a lookup map for fast sink detection and to match sink calls against known patterns. - Added `package-lock.json` for dependency management.
516 lines
13 KiB
Markdown
516 lines
13 KiB
Markdown
# VEX Trust Lattice Specification
|
|
|
|
> **Status**: Implementation Complete (Sprint 7100)
|
|
> **Version**: 1.0.0
|
|
> **Last Updated**: 2025-12-22
|
|
> **Source Advisory**: `docs/product-advisories/archived/22-Dec-2026 - Building a Trust Lattice for VEX Sources.md`
|
|
|
|
## 1. Overview
|
|
|
|
The VEX Trust Lattice provides a mathematically rigorous framework for converting heterogeneous VEX claims from multiple sources into a single, signed, reproducible verdict with a numeric confidence and a complete audit trail.
|
|
|
|
### Goals
|
|
|
|
1. **Explainability**: Every verdict includes a full breakdown of how it was computed
|
|
2. **Reproducibility**: Same inputs always produce identical verdicts (deterministic)
|
|
3. **Auditability**: Signed verdict manifests with pinned inputs for regulatory compliance
|
|
4. **Tunability**: Per-tenant, per-source trust configuration without code changes
|
|
|
|
### Non-Goals
|
|
|
|
- Real-time vulnerability detection (handled by Scanner)
|
|
- VEX document ingestion (handled by Excititor core)
|
|
- Policy enforcement (handled by Policy Engine)
|
|
|
|
---
|
|
|
|
## 2. Trust Vector Model
|
|
|
|
Each VEX source is assigned a 3-component trust vector scored in the range [0..1].
|
|
|
|
### 2.1 Provenance (P)
|
|
|
|
Measures cryptographic and process integrity of the source.
|
|
|
|
| Score | Description |
|
|
|-------|-------------|
|
|
| 1.00 | DSSE-signed, timestamped, Rekor/Git anchored, key in allow-list, rotation policy OK |
|
|
| 0.75 | DSSE-signed + public key known, but no transparency log |
|
|
| 0.40 | Unsigned but retrieved via authenticated, immutable artifact repo |
|
|
| 0.10 | Opaque/CSV/email/manual import |
|
|
|
|
### 2.2 Coverage (C)
|
|
|
|
Measures how well the statement's scope maps to the target asset.
|
|
|
|
| Score | Description |
|
|
|-------|-------------|
|
|
| 1.00 | Exact package + version/build digest + feature/flag context matched |
|
|
| 0.75 | Exact package + version range matched; partial feature context |
|
|
| 0.50 | Product-level only; maps via CPE/PURL family |
|
|
| 0.25 | Family-level heuristics; no version proof |
|
|
|
|
### 2.3 Replayability (R)
|
|
|
|
Measures whether the claim can be deterministically re-derived.
|
|
|
|
| Score | Description |
|
|
|-------|-------------|
|
|
| 1.00 | All inputs pinned (feeds, SBOM hash, ruleset hash, lattice version); replays byte-identical |
|
|
| 0.60 | Inputs mostly pinned; non-deterministic ordering tolerated but stable outcome |
|
|
| 0.20 | Ephemeral APIs; no snapshot |
|
|
|
|
### 2.4 Weight Configuration
|
|
|
|
The base trust score is computed as:
|
|
|
|
```
|
|
BaseTrust(S) = wP * P + wC * C + wR * R
|
|
```
|
|
|
|
**Default weights:**
|
|
- `wP = 0.45` (Provenance)
|
|
- `wC = 0.35` (Coverage)
|
|
- `wR = 0.20` (Replayability)
|
|
|
|
Weights are tunable per policy and sum to 1.0.
|
|
|
|
---
|
|
|
|
## 3. Claim Scoring
|
|
|
|
### 3.1 Base Trust Calculation
|
|
|
|
```csharp
|
|
double BaseTrust(double P, double C, double R, TrustWeights W)
|
|
=> W.wP * P + W.wC * C + W.wR * R;
|
|
```
|
|
|
|
### 3.2 Claim Strength Multipliers (M)
|
|
|
|
Each VEX claim carries a strength multiplier based on evidence quality:
|
|
|
|
| Strength | Value | Description |
|
|
|----------|-------|-------------|
|
|
| ExploitabilityWithReachability | 1.00 | Exploitability analysis + reachability proof subgraph provided |
|
|
| ConfigWithEvidence | 0.80 | Config/feature-flag reason with evidence |
|
|
| VendorBlanket | 0.60 | Vendor blanket statement |
|
|
| UnderInvestigation | 0.40 | "Under investigation" |
|
|
|
|
### 3.3 Freshness Decay (F)
|
|
|
|
Time-decay curve with configurable half-life:
|
|
|
|
```csharp
|
|
double Freshness(DateTime issuedAt, DateTime cutoff, double halfLifeDays = 90, double floor = 0.35)
|
|
{
|
|
var ageDays = (cutoff - issuedAt).TotalDays;
|
|
var decay = Math.Exp(-Math.Log(2) * ageDays / halfLifeDays);
|
|
return Math.Max(decay, floor);
|
|
}
|
|
```
|
|
|
|
**Parameters:**
|
|
- `halfLifeDays = 90` (default): Score halves every 90 days
|
|
- `floor = 0.35` (default): Minimum freshness unless revoked
|
|
|
|
### 3.4 ClaimScore Formula
|
|
|
|
```
|
|
ClaimScore = BaseTrust(S) * M * F
|
|
```
|
|
|
|
**Example calculation:**
|
|
```
|
|
Source: Red Hat (Vendor)
|
|
P = 0.90, C = 0.75, R = 0.60
|
|
BaseTrust = 0.45*0.90 + 0.35*0.75 + 0.20*0.60 = 0.405 + 0.2625 + 0.12 = 0.7875
|
|
|
|
Claim: ConfigWithEvidence (M = 0.80)
|
|
Freshness: 30 days old (F = 0.79)
|
|
|
|
ClaimScore = 0.7875 * 0.80 * 0.79 = 0.498
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Lattice Merge Algorithm
|
|
|
|
### 4.1 Partial Ordering
|
|
|
|
Claims are ordered by a tuple: `(scope_specificity, ClaimScore)`.
|
|
|
|
Scope specificity levels:
|
|
1. Exact digest match (highest)
|
|
2. Exact version match
|
|
3. Version range match
|
|
4. Product family match
|
|
5. Platform match (lowest)
|
|
|
|
### 4.2 Conflict Detection
|
|
|
|
Conflicts occur when claims for the same (CVE, Asset) have different statuses:
|
|
|
|
```csharp
|
|
bool HasConflict(IEnumerable<Claim> claims)
|
|
=> claims.Select(c => c.Status).Distinct().Count() > 1;
|
|
```
|
|
|
|
### 4.3 Conflict Penalty
|
|
|
|
When conflicts exist, apply a penalty to weaker/older claims:
|
|
|
|
```csharp
|
|
const double ConflictPenalty = 0.25;
|
|
|
|
if (contradictory)
|
|
{
|
|
var strongest = claims.OrderByDescending(c => c.Score).First();
|
|
foreach (var claim in claims.Where(c => c.Status != strongest.Status))
|
|
{
|
|
claim.AdjustedScore = claim.Score * (1 - ConflictPenalty);
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4.4 Winner Selection
|
|
|
|
Final verdict is selected by:
|
|
|
|
```csharp
|
|
var winner = scored
|
|
.OrderByDescending(x => (x.Claim.ScopeSpecificity, x.AdjustedScore))
|
|
.First();
|
|
```
|
|
|
|
### 4.5 Audit Trail Generation
|
|
|
|
Every merge produces:
|
|
|
|
```csharp
|
|
public sealed record MergeResult
|
|
{
|
|
public VexStatus Status { get; init; }
|
|
public double Confidence { get; init; }
|
|
public ImmutableArray<VerdictExplanation> Explanations { get; init; }
|
|
public ImmutableArray<string> EvidenceRefs { get; init; }
|
|
public string PolicyHash { get; init; }
|
|
public string LatticeVersion { get; init; }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Policy Gates
|
|
|
|
Gates are evaluated after merge to enforce policy requirements.
|
|
|
|
### 5.1 MinimumConfidenceGate
|
|
|
|
Requires minimum confidence by environment for certain statuses.
|
|
|
|
```yaml
|
|
gates:
|
|
minimumConfidence:
|
|
enabled: true
|
|
thresholds:
|
|
production: 0.75
|
|
staging: 0.60
|
|
development: 0.40
|
|
applyToStatuses:
|
|
- not_affected
|
|
- fixed
|
|
```
|
|
|
|
**Behavior**: Fails if confidence < threshold for specified statuses.
|
|
|
|
### 5.2 UnknownsBudgetGate
|
|
|
|
Limits exposure to unknown/unscored dependencies.
|
|
|
|
```yaml
|
|
gates:
|
|
unknownsBudget:
|
|
enabled: true
|
|
maxUnknownCount: 5
|
|
maxCumulativeUncertainty: 2.0
|
|
```
|
|
|
|
**Behavior**: Fails if:
|
|
- `#unknown_deps > maxUnknownCount`, OR
|
|
- `sum(1 - ClaimScore) > maxCumulativeUncertainty`
|
|
|
|
### 5.3 SourceQuotaGate
|
|
|
|
Prevents single-source dominance without corroboration.
|
|
|
|
```yaml
|
|
gates:
|
|
sourceQuota:
|
|
enabled: true
|
|
maxInfluencePercent: 60
|
|
corroborationDelta: 0.10
|
|
```
|
|
|
|
**Behavior**: Fails if single source influence > 60% AND no second source within delta=0.10.
|
|
|
|
### 5.4 ReachabilityRequirementGate
|
|
|
|
Requires reachability proof for critical vulnerabilities.
|
|
|
|
```yaml
|
|
gates:
|
|
reachabilityRequirement:
|
|
enabled: true
|
|
severityThreshold: CRITICAL
|
|
requiredForStatuses:
|
|
- not_affected
|
|
bypassReasons:
|
|
- component_not_present
|
|
```
|
|
|
|
**Behavior**: Fails if `not_affected` on CRITICAL CVE without reachability proof (unless bypass reason applies).
|
|
|
|
---
|
|
|
|
## 6. Deterministic Replay
|
|
|
|
### 6.1 Input Pinning
|
|
|
|
To guarantee "same inputs → same verdict", pin:
|
|
|
|
- SBOM digest(s)
|
|
- Vuln feed snapshot IDs
|
|
- VEX document digests
|
|
- Reachability graph IDs
|
|
- Policy file hash
|
|
- Lattice version
|
|
- Clock cutoff (evaluation timestamp)
|
|
|
|
### 6.2 Verdict Manifest
|
|
|
|
```json
|
|
{
|
|
"manifestId": "verd:tenant:asset:cve:1234567890",
|
|
"tenant": "acme-corp",
|
|
"assetDigest": "sha256:abc123...",
|
|
"vulnerabilityId": "CVE-2025-12345",
|
|
"inputs": {
|
|
"sbomDigests": ["sha256:..."],
|
|
"vulnFeedSnapshotIds": ["nvd:2025-12-22"],
|
|
"vexDocumentDigests": ["sha256:..."],
|
|
"reachabilityGraphIds": ["graph:..."],
|
|
"clockCutoff": "2025-12-22T12:00:00Z"
|
|
},
|
|
"result": {
|
|
"status": "not_affected",
|
|
"confidence": 0.82,
|
|
"explanations": [...]
|
|
},
|
|
"policyHash": "sha256:...",
|
|
"latticeVersion": "1.2.0",
|
|
"evaluatedAt": "2025-12-22T12:00:01Z",
|
|
"manifestDigest": "sha256:..."
|
|
}
|
|
```
|
|
|
|
### 6.3 Signing
|
|
|
|
Verdict manifests are signed using DSSE with predicate type:
|
|
|
|
```
|
|
https://stella-ops.org/attestations/vex-verdict/1
|
|
```
|
|
|
|
### 6.4 Replay Verification
|
|
|
|
```
|
|
POST /api/v1/authority/verdicts/{manifestId}/replay
|
|
|
|
Response:
|
|
{
|
|
"success": true,
|
|
"originalManifest": {...},
|
|
"replayedManifest": {...},
|
|
"differences": [],
|
|
"signatureValid": true
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Configuration Reference
|
|
|
|
### Full Configuration Example
|
|
|
|
```yaml
|
|
# etc/trust-lattice.yaml
|
|
version: "1.0"
|
|
|
|
trustLattice:
|
|
weights:
|
|
provenance: 0.45
|
|
coverage: 0.35
|
|
replayability: 0.20
|
|
|
|
freshness:
|
|
halfLifeDays: 90
|
|
floor: 0.35
|
|
|
|
conflictPenalty: 0.25
|
|
|
|
defaults:
|
|
vendor:
|
|
provenance: 0.90
|
|
coverage: 0.70
|
|
replayability: 0.60
|
|
distro:
|
|
provenance: 0.80
|
|
coverage: 0.85
|
|
replayability: 0.60
|
|
internal:
|
|
provenance: 0.85
|
|
coverage: 0.95
|
|
replayability: 0.90
|
|
|
|
gates:
|
|
minimumConfidence:
|
|
enabled: true
|
|
thresholds:
|
|
production: 0.75
|
|
staging: 0.60
|
|
development: 0.40
|
|
|
|
unknownsBudget:
|
|
enabled: true
|
|
maxUnknownCount: 5
|
|
maxCumulativeUncertainty: 2.0
|
|
|
|
sourceQuota:
|
|
enabled: true
|
|
maxInfluencePercent: 60
|
|
corroborationDelta: 0.10
|
|
|
|
reachabilityRequirement:
|
|
enabled: true
|
|
severityThreshold: CRITICAL
|
|
```
|
|
|
|
---
|
|
|
|
## 8. API Reference
|
|
|
|
### Endpoints
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/v1/excititor/verdicts/{manifestId}` | Get verdict manifest |
|
|
| GET | `/api/v1/excititor/verdicts` | List verdicts (paginated) |
|
|
| POST | `/api/v1/authority/verdicts/{manifestId}/replay` | Verify replay |
|
|
| GET | `/api/v1/authority/verdicts/{manifestId}/download` | Download signed manifest |
|
|
|
|
See `docs/09_API_CLI_REFERENCE.md` for complete API documentation.
|
|
|
|
---
|
|
|
|
## 9. Examples
|
|
|
|
### Example 1: High-Confidence Verdict
|
|
|
|
**Input:**
|
|
- Red Hat VEX: `not_affected` with `component_not_present`
|
|
- Ubuntu VEX: `not_affected` with `component_not_present`
|
|
|
|
**Calculation:**
|
|
```
|
|
Red Hat: BaseTrust=0.78, M=0.80, F=0.95 → ClaimScore=0.59
|
|
Ubuntu: BaseTrust=0.72, M=0.80, F=0.90 → ClaimScore=0.52
|
|
|
|
No conflict (both agree)
|
|
Winner: Red Hat (higher score)
|
|
Confidence: 0.59
|
|
Gates: All pass (> 0.40 threshold)
|
|
```
|
|
|
|
### Example 2: Conflict Resolution
|
|
|
|
**Input:**
|
|
- Vendor VEX: `not_affected`
|
|
- Internal scan: `affected`
|
|
|
|
**Calculation:**
|
|
```
|
|
Vendor: ClaimScore=0.65
|
|
Internal: ClaimScore=0.55
|
|
|
|
Conflict detected → penalty applied
|
|
Internal adjusted: 0.55 * 0.75 = 0.41
|
|
|
|
Winner: Vendor
|
|
Confidence: 0.65
|
|
Note: Conflict recorded in audit trail
|
|
```
|
|
|
|
---
|
|
|
|
---
|
|
|
|
## 10. Implementation Reference
|
|
|
|
### 10.1 Source Files
|
|
|
|
| Component | Location |
|
|
|-----------|----------|
|
|
| TrustVector | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/TrustVector.cs` |
|
|
| TrustWeights | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/TrustWeights.cs` |
|
|
| ClaimStrength | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/ClaimStrength.cs` |
|
|
| FreshnessCalculator | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/FreshnessCalculator.cs` |
|
|
| DefaultTrustVectors | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/DefaultTrustVectors.cs` |
|
|
| ProvenanceScorer | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/ProvenanceScorer.cs` |
|
|
| CoverageScorer | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/CoverageScorer.cs` |
|
|
| ReplayabilityScorer | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/ReplayabilityScorer.cs` |
|
|
| SourceClassificationService | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/SourceClassificationService.cs` |
|
|
| ClaimScoreMerger | `src/Policy/__Libraries/StellaOps.Policy/TrustLattice/ClaimScoreMerger.cs` |
|
|
| MinimumConfidenceGate | `src/Policy/__Libraries/StellaOps.Policy/Gates/MinimumConfidenceGate.cs` |
|
|
| UnknownsBudgetGate | `src/Policy/__Libraries/StellaOps.Policy/Gates/UnknownsBudgetGate.cs` |
|
|
| SourceQuotaGate | `src/Policy/__Libraries/StellaOps.Policy/Gates/SourceQuotaGate.cs` |
|
|
| ReachabilityRequirementGate | `src/Policy/__Libraries/StellaOps.Policy/Gates/ReachabilityRequirementGate.cs` |
|
|
| TrustVectorCalibrator | `src/Excititor/__Libraries/StellaOps.Excititor.Core/Calibration/TrustVectorCalibrator.cs` |
|
|
|
|
### 10.2 Configuration Files
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `etc/trust-lattice.yaml.sample` | Trust vector weights, freshness parameters, default vectors |
|
|
| `etc/policy-gates.yaml.sample` | Gate thresholds and enable/disable flags |
|
|
| `etc/excititor-calibration.yaml.sample` | Calibration learning parameters |
|
|
|
|
### 10.3 Database Schema
|
|
|
|
- **Calibration manifests**: `src/Excititor/__Libraries/StellaOps.Excititor.Storage.Postgres/Migrations/002_calibration_schema.sql`
|
|
- **Verdict storage**: See Authority module for verdict manifest persistence
|
|
|
|
### 10.4 Test Coverage
|
|
|
|
| Test Suite | Location |
|
|
|------------|----------|
|
|
| TrustVector tests | `src/Excititor/__Tests/StellaOps.Excititor.Core.Tests/TrustVector/` |
|
|
| ClaimScoreMerger tests | `src/Policy/__Tests/StellaOps.Policy.Tests/TrustLattice/` |
|
|
| Gate tests | `src/Policy/__Tests/StellaOps.Policy.Tests/Gates/` |
|
|
| Calibration tests | `src/Excititor/__Tests/StellaOps.Excititor.Core.Tests/Calibration/` |
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
|
|
- [Excititor Architecture](./architecture.md)
|
|
- [Verdict Manifest Specification](../authority/verdict-manifest.md)
|
|
- [Policy Gates Configuration](../policy/architecture.md)
|
|
- [API Reference](../../09_API_CLI_REFERENCE.md)
|
|
|
|
---
|
|
|
|
*Document Version: 1.0.0*
|
|
*Sprint: 7100.0003.0002*
|
|
*Created: 2025-12-22*
|