up
This commit is contained in:
290
docs/guides/epss-integration.md
Normal file
290
docs/guides/epss-integration.md
Normal file
@@ -0,0 +1,290 @@
|
||||
# EPSS Integration Guide
|
||||
|
||||
## Overview
|
||||
|
||||
EPSS (Exploit Prediction Scoring System) is a FIRST.org initiative that provides probability scores for vulnerability exploitation within 30 days. StellaOps integrates EPSS as a risk signal alongside CVSS and KEV (Known Exploited Vulnerabilities) to provide more accurate vulnerability prioritization.
|
||||
|
||||
## How EPSS Works
|
||||
|
||||
EPSS uses machine learning to predict the probability that a CVE will be exploited in the wild within the next 30 days. The model considers:
|
||||
- Vulnerability characteristics (CVSS metrics, CWE, etc.)
|
||||
- Social signals (Twitter mentions, GitHub issues, etc.)
|
||||
- Exploit database entries
|
||||
- Historical exploitation patterns
|
||||
|
||||
EPSS outputs two values:
|
||||
- **Score** (0.0-1.0): Probability of exploitation in next 30 days
|
||||
- **Percentile** (0-100): Ranking relative to all other CVEs
|
||||
|
||||
## How EPSS Affects Risk Scoring in StellaOps
|
||||
|
||||
### Combined Risk Formula
|
||||
|
||||
StellaOps combines CVSS, KEV, and EPSS signals into a unified risk score:
|
||||
|
||||
```
|
||||
risk_score = clamp01(
|
||||
(cvss / 10) + # Base severity (0-1)
|
||||
kevBonus + # +0.20 if in CISA KEV
|
||||
epssBonus # +0.02 to +0.10 based on percentile
|
||||
)
|
||||
```
|
||||
|
||||
### EPSS Bonus Thresholds
|
||||
|
||||
| EPSS Percentile | Bonus | Rationale |
|
||||
|-----------------|-------|-----------|
|
||||
| >= 99th | +10% | Top 1% most likely to be exploited; urgent priority |
|
||||
| >= 90th | +5% | Top 10%; high exploitation probability |
|
||||
| >= 50th | +2% | Above median; moderate additional risk |
|
||||
| < 50th | 0% | Below median; no bonus applied |
|
||||
|
||||
### Example Calculations
|
||||
|
||||
| CVE | CVSS | KEV | EPSS Percentile | Risk Score |
|
||||
|-----|------|-----|-----------------|------------|
|
||||
| CVE-2024-1234 | 9.8 | Yes | 99.5th | 1.00 (clamped) |
|
||||
| CVE-2024-5678 | 7.5 | No | 95th | 0.80 |
|
||||
| CVE-2024-9012 | 6.0 | No | 60th | 0.62 |
|
||||
| CVE-2024-3456 | 8.0 | No | 30th | 0.80 |
|
||||
|
||||
## Implementation Reference
|
||||
|
||||
### IEpssSource Interface
|
||||
|
||||
```csharp
|
||||
// Location: src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Core/Providers/IEpssSources.cs
|
||||
|
||||
public interface IEpssSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns EPSS data for the given CVE identifier, or null if unknown.
|
||||
/// </summary>
|
||||
Task<EpssData?> GetEpssAsync(string cveId, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public sealed record EpssData(double Score, double Percentile, DateTimeOffset? ModelVersion = null);
|
||||
```
|
||||
|
||||
### Risk Providers
|
||||
|
||||
**EpssProvider** - Uses EPSS score directly as risk (0.0-1.0):
|
||||
```csharp
|
||||
// Location: src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Core/Providers/EpssProvider.cs
|
||||
public const string ProviderName = "epss";
|
||||
```
|
||||
|
||||
**CvssKevEpssProvider** - Combined provider using all three signals:
|
||||
```csharp
|
||||
// Location: src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Core/Providers/EpssProvider.cs
|
||||
public const string ProviderName = "cvss-kev-epss";
|
||||
```
|
||||
|
||||
## Policy Configuration
|
||||
|
||||
### Enabling EPSS Integration
|
||||
|
||||
```yaml
|
||||
# etc/risk-engine.yaml
|
||||
risk:
|
||||
providers:
|
||||
- name: cvss-kev-epss
|
||||
enabled: true
|
||||
priority: 1
|
||||
|
||||
epss:
|
||||
enabled: true
|
||||
source: database # or "api" for live FIRST API
|
||||
cache_ttl: 24h
|
||||
|
||||
# Percentile-based bonus thresholds
|
||||
thresholds:
|
||||
- percentile: 99
|
||||
bonus: 0.10
|
||||
- percentile: 90
|
||||
bonus: 0.05
|
||||
- percentile: 50
|
||||
bonus: 0.02
|
||||
```
|
||||
|
||||
### Custom Threshold Configuration
|
||||
|
||||
Organizations can customize EPSS bonus thresholds based on their risk tolerance:
|
||||
|
||||
```yaml
|
||||
# More aggressive (higher bonuses for high-risk vulns)
|
||||
epss:
|
||||
thresholds:
|
||||
- percentile: 99
|
||||
bonus: 0.15
|
||||
- percentile: 95
|
||||
bonus: 0.10
|
||||
- percentile: 75
|
||||
bonus: 0.05
|
||||
|
||||
# More conservative (smaller bonuses)
|
||||
epss:
|
||||
thresholds:
|
||||
- percentile: 99
|
||||
bonus: 0.05
|
||||
- percentile: 95
|
||||
bonus: 0.02
|
||||
```
|
||||
|
||||
## EPSS in Lattice Decisions
|
||||
|
||||
EPSS influences VEX lattice state transitions for vulnerability triage:
|
||||
|
||||
| Current State | EPSS >= 90th Percentile | Recommended Action |
|
||||
|---------------|-------------------------|-------------------|
|
||||
| SR (Static Reachable) | Yes | Escalate to CR (Confirmed Reachable) priority |
|
||||
| SU (Static Unreachable) | Yes | Flag for review - high exploit probability despite unreachable |
|
||||
| DV (Denied by Vendor VEX) | Yes | Review denial validity - exploit activity contradicts vendor |
|
||||
| U (Unknown) | Yes | Prioritize for reachability analysis |
|
||||
|
||||
### VEX Policy Example
|
||||
|
||||
```yaml
|
||||
# etc/vex-policy.yaml
|
||||
lattice:
|
||||
transitions:
|
||||
- from: SR
|
||||
to: CR
|
||||
condition:
|
||||
epss_percentile: ">= 90"
|
||||
action: auto_escalate
|
||||
|
||||
- from: SU
|
||||
to: REVIEW
|
||||
condition:
|
||||
epss_percentile: ">= 95"
|
||||
action: flag_for_review
|
||||
reason: "High EPSS despite static unreachability"
|
||||
```
|
||||
|
||||
## Offline EPSS Data
|
||||
|
||||
EPSS data is included in offline risk bundles for air-gapped environments.
|
||||
|
||||
### Bundle Structure
|
||||
|
||||
```
|
||||
risk-bundle-2025-12-14/
|
||||
├── manifest.json
|
||||
├── kev/
|
||||
│ └── kev-catalog.json
|
||||
├── epss/
|
||||
│ ├── epss-scores.csv.zst # Compressed EPSS data
|
||||
│ └── epss-metadata.json # Model date, row count, checksum
|
||||
└── signatures/
|
||||
└── bundle.dsse.json
|
||||
```
|
||||
|
||||
### EPSS Metadata
|
||||
|
||||
```json
|
||||
{
|
||||
"model_date": "2025-12-14",
|
||||
"row_count": 248732,
|
||||
"sha256": "abc123...",
|
||||
"source": "first.org",
|
||||
"created_at": "2025-12-14T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Importing Offline EPSS Data
|
||||
|
||||
```bash
|
||||
# Import risk bundle (includes EPSS)
|
||||
stellaops offline import --kit risk-bundle-2025-12-14.tar.zst
|
||||
|
||||
# Verify EPSS data imported
|
||||
stellaops epss status
|
||||
# Output:
|
||||
# EPSS Data Status:
|
||||
# Model Date: 2025-12-14
|
||||
# CVE Count: 248,732
|
||||
# Last Import: 2025-12-14T10:30:00Z
|
||||
```
|
||||
|
||||
## Accuracy Considerations
|
||||
|
||||
| Metric | Value | Notes |
|
||||
|--------|-------|-------|
|
||||
| EPSS Coverage | ~95% of NVD CVEs | Some very new CVEs (<24h) not yet scored |
|
||||
| Model Refresh | Daily | Scores can change day-to-day |
|
||||
| Prediction Window | 30 days | Probability of exploit in next 30 days |
|
||||
| Historical Accuracy | ~85% AUC | Based on FIRST published evaluations |
|
||||
|
||||
### Limitations
|
||||
|
||||
1. **New CVEs**: Very recent CVEs may not have EPSS scores yet
|
||||
2. **Model Lag**: EPSS model updates daily; real-world exploit activity may be faster
|
||||
3. **Zero-Days**: Pre-disclosure vulnerabilities cannot be scored
|
||||
4. **Context Blind**: EPSS doesn't consider your specific environment
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Combine Signals**: Always use EPSS alongside CVSS and KEV, not in isolation
|
||||
2. **Review High EPSS**: Manually review vulnerabilities with EPSS >= 95th percentile
|
||||
3. **Track Changes**: Monitor EPSS score changes over time for trending threats
|
||||
4. **Update Regularly**: Keep EPSS data fresh (daily in online mode, weekly for offline)
|
||||
5. **Verify High-Risk**: For critical decisions, verify EPSS data against FIRST API
|
||||
|
||||
## API Usage
|
||||
|
||||
### Query EPSS Score
|
||||
|
||||
```bash
|
||||
# Get EPSS score for a specific CVE
|
||||
stellaops epss get CVE-2024-12345
|
||||
|
||||
# Batch query
|
||||
stellaops epss batch --file cves.txt --output epss-scores.json
|
||||
```
|
||||
|
||||
### Programmatic Access
|
||||
|
||||
```csharp
|
||||
// Using IEpssSource
|
||||
var epssData = await epssSource.GetEpssAsync("CVE-2024-12345", cancellationToken);
|
||||
if (epssData is not null)
|
||||
{
|
||||
Console.WriteLine($"Score: {epssData.Score:P2}");
|
||||
Console.WriteLine($"Percentile: {epssData.Percentile:F1}th");
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### EPSS Data Not Available
|
||||
|
||||
```bash
|
||||
# Check EPSS source status
|
||||
stellaops epss status
|
||||
|
||||
# Force refresh from FIRST API
|
||||
stellaops epss refresh --force
|
||||
|
||||
# Check for specific CVE
|
||||
stellaops epss get CVE-2024-12345 --verbose
|
||||
```
|
||||
|
||||
### Stale EPSS Data
|
||||
|
||||
If EPSS data is older than 7 days:
|
||||
|
||||
```bash
|
||||
# Check staleness
|
||||
stellaops epss check-staleness
|
||||
|
||||
# Import fresh bundle
|
||||
stellaops offline import --kit latest-bundle.tar.zst
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [FIRST EPSS Model](https://www.first.org/epss/)
|
||||
- [EPSS API Documentation](https://www.first.org/epss/api)
|
||||
- [EPSS FAQ](https://www.first.org/epss/faq)
|
||||
- [StellaOps Risk Engine Architecture](../modules/risk-engine/architecture.md)
|
||||
Reference in New Issue
Block a user