Score Policy YAML Format
This reference describes the YAML format Stella Ops uses to configure deterministic vulnerability scoring. It is written for policy authors and operators who tune how findings are scored. The score policy defines how each factor contributes to the final vulnerability score, ensuring reproducible and auditable results.
For the higher-level model of profiles and signals, see Scoring Profiles and Signals Weighting.
Overview
Scores are computed from a small set of weighted factors. Weights and tuning knobs live in a single YAML document so that scoring is transparent, version-controlled, and replayable.
Schema Version
Current version: score.v1
File Location
By default, score policies are loaded from:
etc/score-policy.yaml(production)etc/score-policy.yaml.sample(reference template)
Override via environment variable: STELLAOPS_SCORE_POLICY_PATH
Basic Structure
# Required fields
policyVersion: score.v1
policyId: unique-policy-identifier
# Optional metadata
policyName: "My Organization's Scoring Policy"
description: "Custom scoring weights for our security posture"
# Weight distribution (must sum to 10000 basis points = 100%)
weightsBps:
baseSeverity: 2500 # 25% - CVSS base score contribution
reachability: 2500 # 25% - Code reachability analysis
evidence: 2500 # 25% - KEV, EPSS, exploit evidence
provenance: 2500 # 25% - Supply chain trust signals
Weight Configuration
Weights are specified in basis points (bps) where 10000 bps = 100%. This avoids floating-point precision issues and ensures weights always sum to exactly 100%.
Example: Reachability-Heavy Profile
policyVersion: score.v1
policyId: reachability-focused
weightsBps:
baseSeverity: 2000 # 20%
reachability: 4000 # 40% - Heavy emphasis on reachability
evidence: 2000 # 20%
provenance: 2000 # 20%
Example: Evidence-Heavy Profile
policyVersion: score.v1
policyId: evidence-focused
weightsBps:
baseSeverity: 2000 # 20%
reachability: 2000 # 20%
evidence: 4000 # 40% - Heavy emphasis on KEV/EPSS
provenance: 2000 # 20%
Reachability Configuration
Fine-tune how reachability analysis affects scores:
reachabilityConfig:
reachableMultiplier: 1.5 # Boost for reachable code paths
unreachableMultiplier: 0.3 # Reduction for unreachable code
unknownMultiplier: 1.0 # Default when analysis unavailable
Multiplier Bounds
- Minimum: 0.0
- Maximum: 2.0 (configurable)
- Default for unknown: 1.0 (no adjustment)
Evidence Configuration
Configure how exploit evidence affects scoring:
evidenceConfig:
kevWeight: 1.5 # Boost for KEV-listed vulnerabilities
epssThreshold: 0.5 # EPSS score threshold for high-risk
epssWeight: 1.2 # Weight multiplier for high EPSS
KEV Integration
Known Exploited Vulnerabilities (KEV) from CISA are automatically boosted:
kevWeight: 1.5means 50% score increase for KEV-listed CVEs- Setting
kevWeight: 1.0disables KEV boost
EPSS Integration
Exploit Prediction Scoring System (EPSS) provides probability-based risk:
epssThreshold: Minimum EPSS for applying the weightepssWeight: Multiplier applied when EPSS exceeds threshold
Provenance Configuration
Configure how supply chain trust signals affect scoring:
provenanceConfig:
signedBonus: 0.1 # 10% reduction for signed artifacts
rekorVerifiedBonus: 0.2 # 20% reduction for Rekor-verified
unsignedPenalty: -0.1 # 10% increase for unsigned artifacts
Trust Signals
| Signal | Effect | Use Case |
|---|---|---|
signedBonus | Score reduction | Artifact has valid signature |
rekorVerifiedBonus | Score reduction | Signature in transparency log |
unsignedPenalty | Score increase | No signature present |
Score Overrides
Override scoring for specific CVEs or patterns:
overrides:
# Exact CVE match
- id: log4shell-critical
match:
cvePattern: "CVE-2021-44228"
action:
setScore: 10.0
reason: "Known critical RCE in production"
# Pattern match
- id: log4j-family
match:
cvePattern: "CVE-2021-442.*"
action:
multiplyScore: 1.2
reason: "Log4j family vulnerabilities"
# Severity-based
- id: low-severity-suppress
match:
severityEquals: "LOW"
action:
multiplyScore: 0.5
reason: "Reduce noise from low-severity findings"
# Combined conditions
- id: unreachable-medium
match:
severityEquals: "MEDIUM"
reachabilityEquals: "UNREACHABLE"
action:
multiplyScore: 0.3
reason: "Medium + unreachable = low priority"
Override Actions
| Action | Description | Example |
|---|---|---|
setScore | Force specific score | setScore: 10.0 |
multiplyScore | Apply multiplier | multiplyScore: 0.5 |
addScore | Add/subtract value | addScore: -2.0 |
Match Conditions
| Condition | Description | Example |
|---|---|---|
cvePattern | Regex match on CVE ID | "CVE-2021-.*" |
severityEquals | Exact severity match | "HIGH", "CRITICAL" |
reachabilityEquals | Reachability state | "REACHABLE", "UNREACHABLE", "UNKNOWN" |
packagePattern | Package name regex | "log4j.*" |
Complete Example
policyVersion: score.v1
policyId: production-v2024.12
policyName: "Production Security Policy"
description: |
Balanced scoring policy with emphasis on exploitability
and reachability for production workloads.
weightsBps:
baseSeverity: 2000
reachability: 3000
evidence: 3000
provenance: 2000
reachabilityConfig:
reachableMultiplier: 1.5
unreachableMultiplier: 0.4
unknownMultiplier: 1.0
evidenceConfig:
kevWeight: 1.5
epssThreshold: 0.3
epssWeight: 1.3
provenanceConfig:
signedBonus: 0.1
rekorVerifiedBonus: 0.15
unsignedPenalty: -0.05
overrides:
- id: critical-rce
match:
cvePattern: "CVE-2021-44228|CVE-2022-22965"
action:
setScore: 10.0
reason: "Known critical RCE vulnerabilities"
- id: unreachable-low
match:
severityEquals: "LOW"
reachabilityEquals: "UNREACHABLE"
action:
multiplyScore: 0.2
reason: "Minimal risk: low severity + unreachable"
Validation
Policies are validated against JSON Schema on load:
- Schema validation: Structure and types
- Weight sum check:
weightsBpsmust sum to 10000 - Range checks: Multipliers within bounds
- Override validation: Valid patterns and actions
Programmatic Validation
var validator = new ScorePolicyValidator();
var result = validator.Validate(policy);
if (!result.IsValid)
{
foreach (var error in result.Errors)
{
Console.WriteLine(error);
}
}
Determinism
For reproducible scoring:
- Policy Digest: Each policy has a content-addressed digest
- Replay Manifest: Digest is recorded in scan manifests
- Audit Trail: Policy version tracked with every scan
Digest Format
sha256:abc123def456...
The digest is computed from canonical JSON serialization of the policy, ensuring identical policies always produce identical digests.
Migration
From Hardcoded Weights
- Export current weights to YAML format
- Validate with
stellaops policy validate score.yaml - Deploy to
etc/score-policy.yaml - Restart services to load new policy
Version Upgrades
Future schema versions (e.g., score.v2) will include migration guides and backward compatibility notes.
