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.
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.
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.
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.
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.
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.
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.
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.
git clone https://github.com/joshuaburnie/kev-monitor
cd kev-monitor && npm install
npm run kv:create
Paste the returned id into wrangler.toml under [[kv_namespaces]].
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.
Telegram → @BotFather → /newbot. Save the token. Message your new bot directly before deploying — it cannot initiate the conversation. Get your chat ID from @userinfobot.
Edit src/watchlist.js and add or remove vendor strings to match your environment.
wrangler secret put TELEGRAM_TOKEN
wrangler secret put TELEGRAM_CHAT_ID
wrangler secret put NVD_API_KEY
npm run deploy
The first scheduled run will seed KV silently. Future runs alert on new additions only.
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.
| Resource | Details | Monthly Cost |
|---|---|---|
| Cloudflare Workers | 100k requests/day free — 4 cron runs/day is nothing | $0.00 |
| Cloudflare KV | Reads + writes well within free tier at this cadence | $0.00 |
| CISA KEV catalog | Public feed, no auth required | $0.00 |
| NVD API key | Free from NIST | $0.00 |
| Telegram Bot API | Free | $0.00 |
| Total | Fits within all free tiers | $0.00 |
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.