API & docs

Spydr is plain HTTP. No key, no SDK, no install — if you can run curl, you can use it. Every page on this site is also an API endpoint.

Quick start

Ask for today’s brief — new high and critical CVEs, fresh additions to CISA’s exploited list, and the latest breaches:

shell
curl https://spydr.io

Then narrow it down to what you run:

Terminal
curl "https://spydr.io/threats?q=openssl&limit=3"
spydr · threats · q=openssl                                 163 results · synced 20:44 UTC
──────────────────────────────────────────────────────────────────────────────────────────
 8.7 high      CVE-2026-74891   2026-08-17      EPSS 0.52%  jahlives openssl_encrypt
               openssl_encrypt versions before 1.4.0 contain hardcoded database credentia…
 9.3 critical  CVE-2026-81696   2026-08-27      EPSS 0.25%  jahlives openssl_encrypt
               openssl_encrypt versions before 1.4.9 fail to sanitize terminal control ch…
 9.3 critical  CVE-2026-81695   2026-08-27      EPSS 0.25%  jahlives openssl_encrypt
               openssl_encrypt versions before 1.4.9 fail to escape attacker-controlled k…
──────────────────────────────────────────────────────────────────────────────────────────
page 1 of 55 · web: https://spydr.io/threats?q=openssl&limit=3 · next: &page=2
scripts: add &format=json (or ndjson, csv, rss) · help: curl https://spydr.io/help
Data: This product uses data from the NVD API but is not endorsed or certified by the NVD. CISA KEV · FIRST EPSS.

Open the same URL in a browser and you get the web version. The filters are identical, so you can build a query on the site and paste it into a script. Run curl https://spydr.io/help for a cheat sheet.

One URL, many formats

Spydr picks a format from, in order:

  1. a suffix — /threats.json, .ndjson, .csv, .rss or .txt — or a format= parameter;
  2. an Accept header asking for JSON, NDJSON, CSV, RSS or plain text;
  3. a command-line client — curl, wget, HTTPie, xh or PowerShell get a text table;
  4. everything else — browsers, link previews, crawlers — gets the web page.

Text sent to a terminal is coloured. Add color=0, or use the .txt suffix, for plain output you can pipe into grep or a log. Upstream text is stripped of control characters, so nothing in a CVE description can rewrite your terminal.

Endpoints

PathWhat it returns
/Today’s brief (text or JSON; browsers get the home page).
/threatsCVEs, newest first, with filters below.
/cve/CVE-2024-3400One CVE in full: scores, exploitation, EPSS, references. Fetched from the NVD on demand if we don’t have it yet.
/breachesData breaches, newest additions first.
/helpA cheat sheet for terminals.

Threat filters

ParameterExampleMeaning
qq=nginx,opensslKeywords. Commas mean OR, spaces mean AND. CVE ids work too (q=CVE-2024-3400).
cvsscvss=7Minimum CVSS base score, 0–10.
severityseverity=critical,highOne or more of critical, high, medium, low, none.
exploitedexploited=1Only CVEs in CISA KEV, or with active exploitation reported through CISA’s SSVC data.
kevkev=1Only CVEs in CISA’s Known Exploited Vulnerabilities catalog. With kev=1, since= filters on the date CISA added it.
epssepss=0.1Minimum EPSS probability of exploitation in the next 30 days, 0–1.
sincesince=7dPublished after: 24h, 7d, 2w, 3m or a date like 2026-09-01.
vendor, productvendor=microsoftMatch the vendor or product name.
sortsort=scorerelevance (default with q), published (default), score, epss, kev.
limit, pagelimit=50&page=2Up to 200 per page.

Unknown parameters are ignored and reported in warnings (JSON) or as a note (text). Invalid values return 400 with an explanation.

Breach filters

ParameterExampleMeaning
qq=adobe.comCompany name or domain.
sincesince=30dAdded to Have I Been Pwned after this.
accountsaccounts=1000000Minimum number of affected accounts.
datadata=passwordsExposed data class, e.g. passwords, credit cards, phone numbers.
sortsort=sizeadded (default), breach (breach date) or size.
limit, pagelimit=50Up to 200 per page.

Output & headers

ParameterExampleMeaning
formatformat=jsontext, json, ndjson, csv or rss — or use a suffix: /threats.json, /breaches.rss.
colorcolor=0Plain text for terminals (colour is only added when the response goes to a terminal).
widthwidth=140Text width in columns, 60–240. Default 100.
failfail=1Respond 409 Conflict when anything matches, 200 when nothing does. Made for CI gates.

JSON responses look like this (trimmed):

application/json
{
  "query": { "q": "openssl", "cvss": "7" },
  "count": 3, "total": 12, "page": 1, "limit": 20,
  "updated": { "cves": "2026-09-23T05:43:00Z", "kev": "…", "epss": "…" },
  "links": { "web": "https://spydr.io/threats?q=openssl&cvss=7", "next": "…" },
  "warnings": [],
  "results": [
    {
      "id": "CVE-2026-0000",
      "url": "https://spydr.io/cve/CVE-2026-0000",
      "published": "2026-09-22T15:17:24Z",
      "score": 9.8, "severity": "critical", "cvss_version": "3.1",
      "vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "epss": 0.42, "epss_percentile": 0.97,
      "exploited": true,
      "kev": { "added": "2026-09-22", "due": "2026-10-13", "action": "…", "ransomware": "Unknown" },
      "vendors": ["…"], "products": ["…"], "cwes": ["CWE-787"],
      "description": "…"
    }
  ],
  "attribution": [ { "source": "NVD", "url": "https://nvd.nist.gov", "notice": "…" } ]
}

Useful response headers:

  • X-Spydr-Count — total matches, handy with curl -I.
  • ETag — send it back as If-None-Match and you’ll get 304 Not Modified when nothing changed.
  • Access-Control-Allow-Origin: * — data formats can be fetched from browser code.

Automation recipes

Gate a build on new critical CVEs

With fail=1, Spydr answers 409 when anything matches and 200 when nothing does. Check the status code rather than relying on curl -f, which also fails on network errors and rate limits:

bash
code=$(curl -s -o hits.txt -w '%{http_code}' \
  "https://spydr.io/threats?q=nginx,openssl&cvss=9&since=1d&fail=1")
case $code in
  200) echo "No new critical CVEs" ;;
  409) cat hits.txt; exit 1 ;;              # something matched
  *)   echo "Spydr unavailable ($code)"; exit 2 ;;
esac

GitHub Actions

.github/workflows/security-feed.yml
name: security-feed
on:
  schedule:
    - cron: "0 7 * * 1-5"   # weekdays, 07:00 UTC
  pull_request:

jobs:
  spydr:
    runs-on: ubuntu-latest
    steps:
      - name: Fail on new critical or exploited CVEs in our stack
        run: |
          code=$(curl -s -o hits.txt -w '%{http_code}' \
            "https://spydr.io/threats?q=django,celery,redis,postgresql&cvss=9&since=1d&fail=1")
          cat hits.txt
          case $code in 200) ;; 409) exit 1 ;; *) echo "::warning::Spydr unavailable ($code)" ;; esac

Post exploited CVEs to Slack

shell + cron
#!/bin/sh
# crontab: 0 * * * *  /usr/local/bin/spydr-slack
curl -s "https://spydr.io/threats.json?q=nginx,postgres,openssl&exploited=1&since=1h" \
  | jq -r '.results[] | "*\(.id)* \(.severity) — \(.products[0] // "")\n\(.url)"' \
  | while read -r line; do
      curl -s -X POST -H 'content-type: application/json' \
        -d "$(jq -n --arg t "$line" '{text:$t}')" "$SLACK_WEBHOOK_URL"
    done

jq, NDJSON and CSV

shell
# ids of everything added to KEV in the last day
curl -s "https://spydr.io/threats.json?kev=1&since=24h" | jq -r '.results[].id'

# stream results into another tool, one JSON object per line
curl -s "https://spydr.io/threats.ndjson?q=kubernetes&cvss=7" | while read -r cve; do
  echo "$cve" | jq -r '"\(.id) \(.score)"'
done

# spreadsheet-ready
curl -s -o breaches.csv "https://spydr.io/breaches.csv?since=90d&accounts=1000000"

PowerShell

PowerShell
# PowerShell parses JSON for you
$feed = Invoke-RestMethod "https://spydr.io/threats.json?kev=1&since=7d"
$feed.results | Format-Table id, score, severity, @{n='product';e={$_.products[0]}}

# Or the terminal view
curl.exe "https://spydr.io/threats?exploited=1"

Feed readers

Any list is also an RSS feed: add .rss to the path. For example https://spydr.io/threats.rss?exploited=1 for newly exploited CVEs, or https://spydr.io/breaches.rss for breaches.

Limits & caching

Each client can make 120 requests a minute. Past that you’ll get 429 Too Many Requests with a Retry-After header. The data only changes every hour or two, so polling more often than every 15 minutes gains nothing.

Responses for explicit formats (a suffix or format=) are cacheable for five minutes; fail=1 responses are never cached.

Where the data comes from

CVEs — NVD
Everything published in the last 120 days plus every CVE on CISA’s exploited list, refreshed every two hours. The score shown is the newest CVSS version available (4.0, then 3.1, then 3.0), preferring NVD’s own assessment over the reporting organisation’s. Many new CVEs are scored only by the organisation that reported them.
Exploitation — CISA KEV and SSVC
“Exploited” means the CVE is in CISA’s Known Exploited Vulnerabilities catalog, or CISA’s SSVC assessment records active exploitation. Refreshed hourly.
Exploit prediction — FIRST EPSS
The probability a CVE will be exploited in the next 30 days, updated daily.
Breaches — Have I Been Pwned
Publicly disclosed breaches, refreshed every six hours. Breaches flagged as fabricated, spam lists or retired are left out. Licensed under CC BY 4.0.

This product uses data from the NVD API but is not endorsed or certified by the NVD.