Security · Cloudflare Workers March 2026 Joshua Burnie

Monitoring CISA's exploit catalog for same-day critical alerts

How I built a Cloudflare Worker that watches the CISA Known Exploited Vulnerabilities catalog for new additions, cross-references each watchlist match against NVD for a CVSS score, and fires an immediate Telegram alert when a vendor hits KEV + CRITICAL simultaneously.

Cloudflare Workers CISA KEV NVD API v2 Telegram Bot API Workers KV JavaScript

The CVE feed tells you something might be exploitable. The CISA Known Exploited Vulnerabilities catalog tells you something is being exploited — right now, in the wild. That's a different signal entirely. CISA adds a CVE to the KEV catalog only when there's confirmed, active exploitation. When that lands on a vendor you're running, the remediation window compresses from weeks to hours.

This Worker watches for that moment. Every 6 hours it pulls the full CISA KEV catalog, diffs it against what it's already seen, filters new additions against a vendor watchlist, and enriches each match with a live CVSS score from NVD. If the score is CRITICAL (≥ 9.0), a Telegram alert fires immediately. Same Cloudflare Worker pattern as the CVE Watcher — different data source, sharper signal.

What It Does

The Worker runs every 6 hours on a cron trigger. Each run fetches the full KEV catalog (~1MB JSON, ~1,200+ entries), compares it against the seen set in Workers KV, and processes only new additions. New entries matching the vendor watchlist get enriched with a CVSS score from the NVD API. KEV + CRITICAL means same-day action — an alert fires immediately to Telegram.

telegram · kev-monitor · live example
🔴 KEV + CRITICAL — Same-Day Action Required
CVECVE-2024-20399
VendorCisco
ProductIOS XE Web UI
CVSS Score9.8 (CRITICAL)
KEV Added2024-10-17
CISA Due2024-11-07
Apply mitigations per vendor instructions or discontinue use of the product if mitigations are unavailable.

The alert includes everything needed to act immediately: the CVE ID, vendor, product, CVSS score, the date CISA added it, the CISA-mandated remediation due date, and the required action pulled directly from the KEV feed. No digging through advisories.

How It Works

# Cloudflare Cron — every 6 hours (0 */6 * * *) │ ▼ Worker (index.js) │ ├─► CISA KEV JSON ──► Full catalog fetch (~1MB, ~1,200+ entries) │ Diff against KV seen set → new entries only │ ├─► Vendor watchlist ─► Case-insensitive substring match │ on vendorProject field │ ├─► NVD API v2 ──────► CVSS lookup per watchlist match │ v3.1 → v3.0 → v2.0 precedence │ 200ms delay between requests │ └─► CVSS ≥ 9.0 └─► Telegram alert (same-day action) CVSS < 9.0 └─► Silent (logged only) └─► All new CVE IDs written to KV (mark as seen)

The two-hop data join is the core of this pipeline: CISA's KEV feed confirms active exploitation but carries no CVSS scores. NVD has the scores but no exploitation status. The Worker joins them at runtime — KEV provides the "is it being exploited" signal, NVD provides the "how bad is it" signal. Only entries where both answers are alarming fire an alert.

// bootstrap behavior

On first run, the catalog already contains ~1,200 entries. The Worker detects this (empty seen set + large catalog) and seeds KV silently without alerting. You're watching for new additions, not the full historical catalog. Every subsequent run processes only the delta.

The Stack

Cloudflare Workers
Serverless runtime. Cron triggers, zero infrastructure.
🗄️
Cloudflare KV
Persists seen CVE IDs. Grows ~500 entries/year at CISA's cadence.
🛡️
CISA KEV Catalog
Single JSON feed. Confirmed active exploitation. Updated daily.
🔍
NVD API v2
CVSS score enrichment. v3.1 preferred, falls back to v3.0 and v2.0.
✈️
Telegram Bot API
MarkdownV2 alerts with CVE details and direct NVD links.
🔒
Wrangler CLI
Encrypted secret storage, deploys, and live log tailing.

The Vendor Watchlist

Each entry is matched case-insensitively as a substring against the vendorProject field in the KEV catalog. The default watchlist covers the vendors most frequently appearing in KEV historically — network security, remote access, and core infrastructure.

Network / Firewall / VPN
CiscoPalo Alto NetworksFortinetJuniperSonicWallF5
Remote Access / Identity
IvantiPulse SecureCitrix
Infrastructure
VMwareMicrosoft

Edit src/watchlist.js to match your environment. Check the live KEV catalog for the exact vendor name strings CISA uses if you need precise matching.

Step-by-Step Build

01

Clone the repo and install dependencies

git clone https://github.com/joshuaburnie/kev-monitor
cd kev-monitor && npm install
02

Create the KV namespace

npm run kv:create

Paste the returned id into wrangler.toml under [[kv_namespaces]].

03

Get a free NVD API key

Without a key: 5 requests per 30 seconds. With a key: 50 per 30 seconds. Request free at nvd.nist.gov. Activates within 24 hours. If your watchlist is narrow, you can run keyless and the 200ms request delay will keep you under the free limit.

04

Create your Telegram bot

Telegram → @BotFather/newbot. Save the token. Message your new bot directly before deploying — it cannot initiate the conversation. Get your chat ID from @userinfobot.

05

Configure your watchlist

Edit src/watchlist.js and add or remove vendor strings to match your environment.

06

Upload secrets

wrangler secret put TELEGRAM_TOKEN
wrangler secret put TELEGRAM_CHAT_ID
wrangler secret put NVD_API_KEY
07

Deploy

npm run deploy

The first scheduled run will seed KV silently. Future runs alert on new additions only.

08

Trigger manually to verify

curl -X POST https://kev-monitor.<your-subdomain>.workers.dev/run

Returns 202 Accepted immediately. Check wrangler tail to confirm the run completed and KV was seeded.

Cost

ResourceDetailsMonthly Cost
Cloudflare Workers100k requests/day free — 4 cron runs/day is nothing$0.00
Cloudflare KVReads + writes well within free tier at this cadence$0.00
CISA KEV catalogPublic feed, no auth required$0.00
NVD API keyFree from NIST$0.00
Telegram Bot APIFree$0.00
TotalFits within all free tiers$0.00

Design Decisions

// why these choices
  • CISA KEV over NVD alone — KEV is a confirmed exploitation signal, not a theoretical severity score. A CVSS 9.8 with no exploitation evidence is lower priority than a CVSS 7.5 that CISA has confirmed active.
  • Both signals required — KEV alone without a CRITICAL score generates noise. CVSS CRITICAL without KEV is theoretical. The intersection is the actionable signal.
  • Full catalog diff, not streaming — CISA provides a single JSON file updated daily. Diffing against KV is simpler and more reliable than trying to detect incremental changes.
  • All new entries marked seen regardless of score — A Cisco CVE with CVSS 5.8 gets marked seen on first run. The 6-hour re-run won't re-process it hoping the score changed.
  • CVSS version precedence — NVD returns multiple metric versions. The Worker prefers v3.1 → v3.0 → v2.0 in order, so you always get the most current scoring schema.

What's Next

The natural extension is a daily digest for non-critical KEV additions — buffer watchlist matches below the CRITICAL threshold throughout the day and flush them in a single Telegram message each morning. The KV shape is already set up to support a second key for the digest buffer.

I'm also looking at per-vendor CVSS thresholds — Ivanti and Citrix have such high historical exploitation rates that a KEV addition at any CVSS score probably warrants an alert. The watchlist structure in src/watchlist.js could be extended from strings to objects with per-vendor threshold overrides.