Skip to main content

epss-client

A Python client and CLI for the EPSS (Exploit Prediction Scoring System) API.

Fetch exploit prediction scores for CVEs, search with filters, track score changes over time, and download bulk data with this lightweight, zero-overhead client.

Installation

pip install epss-client

Quick Start (Python API)

from epss import EPSSClient

client = EPSSClient()

# Get EPSS score for a single CVE
resp = client.get("CVE-2022-27225")
print(resp.data[0])  # EPSSScore object

# Batch lookup
resp = client.get(["CVE-2022-27225", "CVE-2022-27223"])

# Search with filters
resp = client.search(epss_gt=0.9, limit=50)

# Top 10 CVEs by EPSS score
resp = client.top(10, by="epss")

# Stream all matching records
for page in client.iter_pages(epss_gt=0.5):
    for score in page.data:
        print(score.cve, score.epss, score.risk_label())

# Historical data
resp = client.get("CVE-2022-27225", date="2022-03-05")

# Time series (last 30 days)
resp = client.get("CVE-2022-25204", scope="time-series")
for ts in resp.data[0].time_series:
    print(ts.date, ts.epss)

# Compare scores between two dates
comparison = client.compare("CVE-2022-27225", date1="2022-03-01", date2="2022-04-01")

# Download bulk CSV data
records = client.get_bulk_csv(date="2022-03-05", min_epss=0.5)

Quick Start (CLI)

# Get EPSS score
epss get CVE-2022-27225

# Batch lookup
epss get CVE-2022-27225 CVE-2022-27223

# Search (default: top 100 by EPSS descending)
epss search --epss-gt 0.9

# Top 20 CVEs
epss top 20

# Top 10 by percentile
epss top 10 --by percentile

# Time series (last 30 days)
epss time-series CVE-2022-25204

# Compare between two dates
epss compare CVE-2022-27225 --date1 2022-03-01 --date2 2022-04-01

# Download bulk CSV
epss bulk --date 2022-03-05

# Filter bulk data by EPSS score
epss bulk --min-epss 0.5

# JSON output
epss search --epss-gt 0.9 -o json

# CSV output
epss search --percentile-gt 0.95 -o csv

Client Reference

EPSSClient

from epss import EPSSClient

client = EPSSClient(timeout=30)

Parameters:

  • timeout (int): HTTP timeout in seconds. Default: 30.
  • session (requests.Session, optional): Pre-configured requests session for custom proxies, retry logic, or TLS verification.
  • user_agent (str, optional): Custom User-Agent header. Default: epss-client/{version} (python-requests).

get()

Fetch EPSS scores for one or more CVEs.

# Single CVE
resp = client.get("CVE-2022-27225")

# Batch lookup
resp = client.get(["CVE-2022-27225", "CVE-2022-27223"])

# Historical data (specific date)
resp = client.get("CVE-2022-27225", date="2022-03-05")

# Time series (last 30 days)
resp = client.get("CVE-2022-25204", scope="time-series")

Returns: EPSSResponse with .data list of EPSSScore objects.

search()

Query the database with optional filters. All parameters are combinable.

# Top CVEs by EPSS (default)
resp = client.search(epss_gt=0.9, limit=100)

# CVEs above a percentile threshold
resp = client.search(percentile_gt=0.95)

# By date
resp = client.search(date="2022-03-05", epss_gt=0.7)

# With custom ordering and pagination
resp = client.search(
    epss_gt=0.5,
    order="!epss",  # descending
    limit=50,
    offset=100,
)

Parameters:

  • date (str or datetime.date): Restrict to a specific date. Format: YYYY-MM-DD.
  • epss_gt (float): Only return CVEs with EPSS score greater than this value.
  • epss_lt (float): Only return CVEs with EPSS score less than this value.
  • percentile_gt (float): Only return CVEs with percentile greater than this.
  • percentile_lt (float): Only return CVEs with percentile less than this.
  • order (str): Sort order. Options: epss, !epss, percentile, !percentile. Default: !epss.
  • limit (int): Results per page. Default: 100.
  • offset (int): Pagination offset. Default: 0.

Returns: EPSSResponse.

top()

Convenience wrapper around search() to get the top N CVEs.

resp = client.top(100, by="epss", date="2022-03-05")

Parameters:

  • n (int): Number of results. Default: 100.
  • by (str): Sort by epss or percentile. Default: epss.
  • date (str or datetime.date, optional): Restrict to a specific date.

Returns: EPSSResponse.

iter_pages()

Memory-safe pagination generator. Yields EPSSResponse objects until all results are exhausted.

for page in client.iter_pages(epss_gt=0.5, page_size=1000):
    for score in page.data:
        process(score)

Useful for traversing large result sets without loading everything into memory.

get_all()

Fetch all matching records across all pages into a single list.

# All CVEs with EPSS > 0.9
scores = client.get_all(epss_gt=0.9)

# Cap results to avoid memory issues
scores = client.get_all(epss_gt=0.5, max_records=10000)

Parameters:

  • max_records (int, optional): Stop after this many records. Useful for large queries.

Returns: list[EPSSScore].

compare()

Compare EPSS scores for one or more CVEs between two dates.

comparison = client.compare(
    ["CVE-2022-27225", "CVE-2022-27223"],
    date1="2022-03-01",
    date2="2022-04-01",
)

for cve_id, (score1, score2) in comparison.items():
    delta = score2.epss - score1.epss
    print(f"{cve_id}: {delta:+.4f}")

Returns: dict[str, tuple[EPSSScore, EPSSScore]] where values are (score_at_date1, score_at_date2).

get_bulk_csv()

Download and parse the bulk EPSS CSV for a specific date from empiricalsecurity.com.

# Today's data
records = client.get_bulk_csv()

# Specific date
records = client.get_bulk_csv(date="2022-03-05")

# Filter by EPSS score
records = client.get_bulk_csv(min_epss=0.5)

Returns: list[CSVRecord].

Data Models

EPSSScore

Represents a single CVE EPSS score.

score = resp.data[0]
print(score.cve)        # "CVE-2022-27225"
print(score.epss)       # 0.001870000
print(score.percentile) # 0.401060000
print(score.date)       # datetime.date(2026, 5, 4)
print(score.risk_label())  # "INFORMATIONAL"

Risk labels:

  • CRITICAL: epss >= 0.7
  • HIGH: epss >= 0.4
  • MEDIUM: epss >= 0.1
  • LOW: epss >= 0.01
  • INFORMATIONAL: epss < 0.01

EPSSResponse

A paginated API response.

resp = client.search()
print(resp.status)       # "OK"
print(resp.total)        # 100000
print(resp.offset)       # 0
print(resp.limit)        # 100
print(resp.has_more)     # True
print(resp.next_offset)  # 100
print(resp.data)         # list[EPSSScore]

EPSSTimePoint

A single entry in a time-series response.

resp = client.get("CVE-2022-25204", scope="time-series")
for ts in resp.data[0].time_series:
    print(ts.date, ts.epss, ts.percentile)

CSVRecord

A single row from bulk CSV data.

records = client.get_bulk_csv()
for record in records:
    print(record.cve, record.epss, record.percentile, record.date)

Error Handling

All exceptions inherit from EPSSError for convenient catching.

from epss import (
    EPSSError,
    EPSSAPIError,
    EPSSValidationError,
    EPSSNetworkError,
    EPSSCSVError,
)

try:
    resp = client.get("CVE-2022-27225")
except EPSSAPIError as e:
    print(f"API error: {e.status_code}")
    if e.response_body:
        print(e.response_body)
except EPSSNetworkError as e:
    print(f"Network error: {e}")
except EPSSValidationError as e:
    print(f"Invalid request: {e}")
except EPSSCSVError as e:
    print(f"CSV download failed: {e}")

Pagination Guide

Small result sets

Use search() directly:

resp = client.search(epss_gt=0.9, limit=100)
all_records = resp.data

Large result sets

Use iter_pages() for memory efficiency:

for page in client.iter_pages(epss_gt=0.5, page_size=1000):
    for score in page.data:
        # process one at a time
        process(score)

Or get_all() with a safety cap:

scores = client.get_all(epss_gt=0.5, max_records=10000)

Output Formats (CLI)

Table (default)

CVE | EPSS | Percentile | Risk | Date
...
epss search --epss-gt 0.9

JSON

epss search --epss-gt 0.9 -o json

CSV

epss search --epss-gt 0.9 -o csv > results.csv

Development

Install with dev dependencies

pip install -e ".[dev]"

Run tests

pytest -v

Type checking

mypy src/epss

Linting

ruff check src/epss
black src/epss

Build package

python -m build

Publish to PyPI

twine upload dist/*

License

MIT License. See LICENSE for details.

Links

Release files for epss-py 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for epss-py 0.1.0
File Size Uploaded
epss_py-0.1.0.tar.gz 18.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for epss-py 0.1.0
File Interpreter ABI Platform
epss_py-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 32.8 kB

Release files / epss_py-0.1.0.tar.gz

Download URL epss_py-0.1.0.tar.gz
Size 18.5 kB
Tags Source
SHA-256 checksum
How to use checksums
7d780450eebdef878bfc7b1f6cca318255325b044415f67505d2542c0b2866e0
BLAKE2b-256 checksum
How to use checksums
c75e365ce94e74b29fd040c0ad7f98f9969445bd7ed0e1b4242fcdaef507f56d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / epss_py-0.1.0-py3-none-any.whl

Download URL epss_py-0.1.0-py3-none-any.whl
Size 14.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
856e68e21e24fa46b67dec3df5f3b8f679867e2c7a237e08e27b36475ca06e6a
BLAKE2b-256 checksum
How to use checksums
57cd7bdd0a0206c22573036982c67f01c64c67b0184a723620114a4160e29bf2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page