icsprio
Status: v1.0.0 (verified — see Verification) | Maintainer: Friday Ogochukwu Ikwuogu, ORCID 0009-0009-2222-1318 | License: code MIT, joined data CC BY 4.0
icsprio is an open Python package that fetches, joins, and prioritizes ICS (industrial control systems) vulnerability intelligence from five public sources — CISA ICS Advisories, the CISA Known Exploited Vulnerabilities (KEV) catalog, FIRST.org's EPSS, CISA's Vulnrichment SSVC/CVSS enrichment, and MITRE ATT&CK for ICS — into one deterministic, reproducible table with an OT-relevant priority score. It is built for operators, researchers, and auditors who need a defensible, explainable answer to "which of these ICS advisories should we act on first," instead of five browser tabs and a spreadsheet.
Every number icsprio produces is reproducible: given the same fetched data and the same scoring weights, two runs never disagree, and every weight and mapping decision is documented and author-reviewed, not a black box.
What is here
icsprio/ the installable package (fetchers, join, scoring, QA, CLI)
icsprio/reference_data/ cwe_to_attack_ics.csv — the author-reviewed CWE->ATT&CK crosswalk
code/ numbered scripts in run order (thin wrappers over icsprio/)
data/raw/ inputs as fetched, with PROVENANCE.txt (created by `fetch`)
data/processed/ joined table, qa_report.txt, stats.json (created by `build`)
docs/ CODEBOOK, SCORING, ATTACK_MAPPING, LIMITATIONS, VERIFY_CHECKLIST, NEXT_STEPS
tests/ offline pytest suite (fixtures only, no network calls)
paper/ JOSS-format paper draft (prepared, not yet submitted)
Install
pip install icsprio # once published to PyPI
# or, from a clone:
pip install -e ".[dev,parquet]"
Requires Python 3.9+. Runtime dependencies are deliberately minimal:
requests, pandas, click, PyYAML.
Run it
icsprio run # fetch + join + score + QA in one call
icsprio report # print the QA report
or, to re-score already-fetched data (e.g. after editing docs/SCORING.md's
weights) without hitting the network again:
icsprio fetch --since-year 2023
icsprio build --weights-file my_weights.yaml
or the numbered scripts, if you'd rather not install the CLI:
python code/01_fetch.py --since-year 2023
python code/02_build.py
python code/03_qa.py
A stranger should be able to run any of the above from this README alone
and get data/processed/icsprio_joined.csv and qa_report.txt.
Default scope
By default, fetch pulls ICS advisories from the last 3 years
(--since-year <current year - 3>), not the full historical archive. This
is a deliberate default, not a limitation of the data — see
docs/LIMITATIONS.md for why, and pass
--since-year 2010 (or any earlier year) for a full historical pull. Set
the GITHUB_TOKEN environment variable to raise GitHub's API rate limit
for larger pulls.
Sources
| Source | What it provides | Vintage | License / terms | Accessed |
|---|---|---|---|---|
| CISA ICS Advisories (CSAF 2.0), via cisagov/CSAF | Advisory metadata, vendor/product, CVEs | ongoing | U.S. Government work, public domain | 2026-09-13 |
| CISA KEV catalog | Confirmed real-world exploitation | updated continuously | U.S. Government work, public domain | 2026-09-13 |
| FIRST.org EPSS | Exploitation-likelihood score | daily, back to 2021-04-14 | FIRST.org terms of use | 2026-09-13 |
| CISA Vulnrichment | SSVC decision points, CVSS, CWE | ongoing (partial CVE coverage) | CC0-1.0 | 2026-09-13 |
| MITRE ATT&CK for ICS | Adversary technique catalog | versioned releases | ATT&CK Terms of Use | 2026-09-13 |
How prioritization works
priority_score (0-100) is a deterministic weighted combination of KEV
status, EPSS percentile, and Vulnrichment's SSVC decision points. The exact
weights and the rationale for each are in docs/SCORING.md
— read that before trusting or citing a score; it is icsprio's own
analytic contribution, not a value CISA or FIRST publishes. attack_technique_ids
comes from a documented, author-reviewed CWE-to-ATT&CK-for-ICS heuristic
crosswalk (no authoritative CVE-to-technique mapping exists) — see
docs/ATTACK_MAPPING.md.
Headline numbers
From data/processed/stats.json, generated by a real icsprio run against
live sources (2026-09-13, --since-year 2023):
- 1,685 advisories fetched, 8,653 (advisory, CVE) rows, 7,107 unique CVEs
- Join match rates: KEV 1.0%, EPSS 99.7%, Vulnrichment 78.9%, ATT&CK-for-ICS mapped 5.9%
- Priority bands: Critical 83, High 37, Medium 1,978, Low 6,555
- 0 sanity-check problems
Re-run icsprio run yourself and these numbers regenerate from your own
live fetch — never take them as static.
Verification
This release has cleared the author verification gate
(docs/VERIFY_CHECKLIST.md): a live icsprio run
against real sources, the full pytest suite passing, and a hand review of
docs/SCORING.md's weights and icsprio/reference_data/cwe_to_attack_ics.csv's
crosswalk.
See docs/LIMITATIONS.md for what remains provisional by design (e.g. the crosswalk is a documented heuristic, not a MITRE mapping) rather than unfinished.
Publishing
Published on GitHub and archived on Zenodo (10.5281/zenodo.22732040); see docs/PUBLISH_GUIDE.md for PyPI steps.
Citation
See CITATION.cff. DOI: 10.5281/zenodo.22732040.
Contributing
See CONTRIBUTING.md.
Authors
See AUTHORS.json — the single source of truth for authorship across this README, CITATION.cff, the JOSS paper, and Zenodo metadata.
Metadata
Release files for icsprio 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| icsprio-1.0.0.tar.gz | 46.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| icsprio-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 81.7 kB
Release files / icsprio-1.0.0.tar.gz
| Download URL | icsprio-1.0.0.tar.gz |
|---|---|
| Size | 46.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
93056384a40e98130bb363bc65b5456ec17a37dbaa8547dddae6419dff72b50c
|
|
BLAKE2b-256 checksum How to use checksums |
997e1aabf05936ebcc6dc5375e6288cf1c8f99a0aed0f9445ee5910c7c207aa5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / icsprio-1.0.0-py3-none-any.whl
| Download URL | icsprio-1.0.0-py3-none-any.whl |
|---|---|
| Size | 35.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9f31191955c709ee10ed69da8c4efdd2dbc0ef9277357106b10871f23b12aeb3
|
|
BLAKE2b-256 checksum How to use checksums |
f50049cd941ff3853c6e05e73ca5124fd485be2068d8b0a7bcff3226b464be88
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|