Skip to main content

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

Project description

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

epss_py-0.1.0.tar.gz (18.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

epss_py-0.1.0-py3-none-any.whl (14.3 kB view details)

Uploaded Python 3

File details

Details for the file epss_py-0.1.0.tar.gz.

File metadata

  • Download URL: epss_py-0.1.0.tar.gz
  • Upload date:
  • Size: 18.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for epss_py-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7d780450eebdef878bfc7b1f6cca318255325b044415f67505d2542c0b2866e0
MD5 ec1b3bbfdc535f39cecc302bb043f219
BLAKE2b-256 c75e365ce94e74b29fd040c0ad7f98f9969445bd7ed0e1b4242fcdaef507f56d

See more details on using hashes here.

File details

Details for the file epss_py-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: epss_py-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for epss_py-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 856e68e21e24fa46b67dec3df5f3b8f679867e2c7a237e08e27b36475ca06e6a
MD5 0eb366a6621a303f338ef45821dacaed
BLAKE2b-256 57cd7bdd0a0206c22573036982c67f01c64c67b0184a723620114a4160e29bf2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page