291 lines
7.7 KiB
Markdown
291 lines
7.7 KiB
Markdown
# 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)
|