Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

Local Exploit Hazard Model

A Bayesian framework that converts the global exploitation probabilities of an exploit likelihood model (ELM) such as EPSS into a defender's own daily exploit hazard rate, aggregated from individual vulnerability instances up to the whole organization.

This repository is the research artifact for the paper Modeling Local Exploit Hazard — A Bayesian Framework for Quantifying Exploit Risk and Operational Efficiency (arXiv:2607.24618): standalone notebooks that implement the model end to end, the supporting modules that hold the paper's equations, and the scripts that build the public datasets the analysis runs on — including the Weibull calibration pipeline that fits the hazard shape parameter from observed exploitation timing.

The paper is the source of truth for the model. Read it alongside the code: every module and notebook cites the section or equation it implements.

The question it answers

Given my set of exposed vulnerabilities, how many exploit events should I expect in a given timeframe, and how can I efficiently reduce that number?

The model measures the exploit-prevention effectiveness of deployed controls as a probability distribution (seeded from a subject-matter-expert opinion pool, updated by Beta-Binomial inference), applies it to ELM scores by attack-vector alignment, and converts the result to a hazard rate using standard survival-analysis techniques. Because hazards are additive under independence, per-vulnerability rates sum up to host, network, business unit, and organization. Candidate remediation actions are then ranked by the hazard they remove.

Model at a glance

Level Output Paper
Control effectiveness Beta posterior per control (SME pool → telemetry update) §3.1
Applied likelihood EL_ic = EL_i (1 - CE), aligned by CVSS attack vector §3.2
Host aggregation EL_g = 1 - ∏(1 - EL_ic) §3.4
Hazard h = -ln(1 - EL_g) / t_ELM; exponential or KEV-calibrated Weibull §3.5
Scaling H_agg = Σ h_i to any grouping §3.6
Remediation actions ranked by ΔH_agg removed §3.7

Repository layout

.
├── LICENSE
└── code/
    ├── requirements.txt                  # all Python dependencies
    ├── notebooks/
    │   ├── exploit_hazard_end_to_end.ipynb   # full pipeline, Level 1 → remediation
    │   ├── sensitivity_analysis.ipynb        # sensitivity analysis on real EPSS/CVE data
    │   └── REQUIREMENTS.md                   # environment, run guide, scope
    └── scripts/
        ├── hazard_model.py               # paper equations as pure functions
        ├── synthetic_org.py              # reproducible ~3,000-host synthetic inventory
        ├── sensitivity_toolkit.py        # real-data organization, layered controls, SA methods
        ├── download_kev.py               # fetch the CISA KEV catalog
        ├── enrich_cve_bundle.py          # add NVD dates + KEV timing → time-to-exploit
        ├── calibrate_weibull.py          # fit the Weibull shape parameter k from TTE
        ├── build_real_cve_bundle.py      # assemble the real-CVE bundle (EPSS + CVSS + KEV)
        ├── test_hazard_model.py          # tests for the paper's equations
        ├── test_sensitivity_toolkit.py   # tests for the sensitivity toolkit
        └── README.md                     # script details

No data ships with this repository. The scripts in code/scripts/ build it from public sources (FIRST/EPSS, the CVE List, CISA KEV, NVD) into a gitignored code/data/ directory. See Data below.

Quick start

From the repository root:

python -m venv .venv
source .venv/bin/activate
pip install -r code/requirements.txt

Python 3.9 or newer.

Run the model

code/notebooks/exploit_hazard_end_to_end.ipynb runs the full pipeline on a seeded synthetic organization. It needs no data, no network, no API keys — every input is either a literal in the notebook or drawn from a seeded RNG. The notebook locates the repository itself, so it runs from any working directory:

jupyter notebook code/notebooks/exploit_hazard_end_to_end.ipynb

or execute headless:

jupyter nbconvert --to notebook --execute --inplace \
    code/notebooks/exploit_hazard_end_to_end.ipynb

Runtime is well under a minute. Figures render inline — the notebooks write nothing to disk. See code/notebooks/REQUIREMENTS.md for the full run guide and scope.

Sensitivity analysis

code/notebooks/sensitivity_analysis.ipynb runs a thorough sensitivity analysis of the model — one-at-a-time tornado, elasticities, layered-control ablation, Monte-Carlo uncertainty propagation, an exact per-instance hazard decomposition, variance-based global sensitivity (Sobol + PRCC with bootstrap CIs), and decision-robustness of the remediation ranking.

It is grounded in real data: real EPSS scores, real CVEs, real CVSS attack vectors, and real KEV membership, mapped onto a synthetic device inventory with multiple layered controls composed per host. A real vulnerability inventory is proprietary; the synthetic one stands in for it.

This notebook requires the CVE bundle, which you build first (see Data):

python code/scripts/build_real_cve_bundle.py

Tests

python -m pytest code/scripts/

Covers the hazard equations (exponential/Weibull agreement at k = 1, scale anchoring, aggregation round-trips, the calibrated shape constant) and the sensitivity toolkit. Tests that need the CVE bundle skip cleanly when it has not been built.

Data

Nothing in code/data/ is committed — the directory is gitignored and built on demand from public sources. Two independent pipelines produce it, and both require network access.

Keeping the data out of the repository means the artifact stays small and every input is traceable to its upstream source rather than to a snapshot of unclear provenance. The cost is that you build it yourself. Reproducibility is preserved by pinning the snapshot date: --date 2026-07-23 is the snapshot the paper uses, and the EPSS archive is immutable per day, so that flag reproduces the paper's inputs exactly.

The real-CVE bundle (for the sensitivity notebook)

python code/scripts/build_real_cve_bundle.py

Assembles real EPSS scores (FIRST/EPSS daily archive), real CVSS attack vectors and real KEV membership (CVE List CVEProject/cvelistV5, including the CISA-ADP type: kev metric) into code/data/real_cve_bundle.csv. Nothing in the bundle is fabricated or imputed.

To reproduce the paper's inputs exactly:

python code/scripts/build_real_cve_bundle.py --date 2026-07-23 --extra 5500

All sources are fetched from GitHub, not the NVD API, so there is no API key and no rate-limit wait. Expect a few minutes for the paper-sized bundle; --extra and --cap trade size for speed.

The Weibull calibration (for the hazard shape parameter)

The shape parameter k is fitted from CISA KEV timing — the interval between a vulnerability's disclosure and its first confirmed exploitation. The paper's calibrated value, k ≈ 0.605, is a constant in code/scripts/hazard_model.py, so the notebooks do not need this pipeline; run it only to recalibrate:

python code/scripts/download_kev.py          # fetch the KEV catalog
python code/scripts/enrich_cve_bundle.py     # compute time-to-exploit per CVE
python code/scripts/calibrate_weibull.py     # fit k, write weibull_calibration.json

See code/scripts/README.md for details on both pipelines.

Determinism

Every stochastic step draws from a seeded numpy.random.Generator (SEED = 20260723). Re-running reproduces the same organization, the same pooled statistics, and the same figures. Changing the seed changes the synthetic organization but must not change any qualitative conclusion — if it does, that is a finding worth reporting, not noise to reroll.

The notebooks assert rather than narrate: each stage checks its own output, so a broken run stops instead of quietly producing a plausible-looking figure.

License

MIT — see LICENSE. This covers everything in this repository.

The paper is not distributed here. It lives on arXiv under CC BY-SA, which governs reuse of the paper itself. That share-alike condition does not reach this code — the MIT-licensed implementation can be reused without triggering it.

Authors

Stephen Shaffer · Laura Voicu

About

A Bayesian framework that converts the global exploitation probabilities of an exploit likelihood model (ELM) such as EPSS into a defender's own daily exploit hazard rate, aggregated from individual vulnerability instances up to the whole organization.

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages