How I built a Cloudflare Worker that polls the NVD API daily for new HIGH and CRITICAL CVEs across 20 watched security products — and fires structured alerts to Telegram and Slack the moment they drop.
Every security professional has been in this situation: a vendor emails you about a critical vulnerability in their product — days after it dropped in NVD. By then you're already behind. I wanted a system that flipped this around: alert me the moment a HIGH or CRITICAL CVE lands, before the vendor advisory, before the patch Tuesday roundup.
So I built a Cloudflare Worker that polls the NVD API daily across 20 watched security products, deduplicates against KV, and fires structured alerts to both Telegram and Slack simultaneously. No servers. No managed services. $0/month on the free tier.
The worker runs on a daily cron schedule — 9am UTC by default. Each run searches NVD for CVEs published in the past 24 hours across 20 watched products. Anything scoring CVSS ≥ 7.0 gets checked against a dedup store and, if new, fires to both channels at once.
Each cycle starts with a summary — critical count, high count, total new — then individual alerts sorted by CVSS score descending, capped at 10 per cycle to prevent flooding. In Slack, alerts render as Block Kit cards with two-column field layouts and clickable CVE links.
The NVD API v2 is queried once per product per run using keywordSearch with the human-readable product name. The cpeName wildcard parameter silently returns empty results — keywordSearch matches how NVD's own search UI works. Deduplication lives in Cloudflare KV: each seen CVE ID is written with a 30-day TTL. You only hear about a CVE once.
Twenty products across eight security categories — the most commonly targeted by nation-state actors and ransomware groups based on CISA KEV data and historical breach analysis.
Add or remove products by editing src/cpes.ts. Each entry has a name, CPE string, and category. The name is used as the NVD search keyword and appears in all alerts.
git clone https://github.com/joshuaburnie/cve-watcher
cd cve-watcher && npm install
Without a key: 5 requests per 30 seconds — too slow for 20 products. With a key: 50 per 30 seconds. Request free at nvd.nist.gov. Activates within 24 hours.
npx wrangler kv namespace create CVE_SEEN
Paste the returned id into wrangler.toml under [[kv_namespaces]].
Telegram → @BotFather → /newbot. Save the token. Message your new bot directly before deploying — it cannot initiate the conversation. Get your user ID from @userinfobot.
Go to api.slack.com/apps/new → From scratch → Incoming Webhooks → Add webhook to your channel → copy the URL.
npx wrangler secret put NVD_API_KEY
npx wrangler secret put TELEGRAM_BOT_TOKEN
npx wrangler secret put TELEGRAM_CHAT_ID
npx wrangler secret put SLACK_WEBHOOK_URL
npx wrangler secret put TRIGGER_SECRET
npm run deploy
Confirm output shows KV namespace ID, POLL_HOURS: "24", and schedule: 0 9 * * *.
Set POLL_HOURS = "720" in wrangler.toml, redeploy, then trigger:
curl "https://cve-watcher.yourname.workers.dev/trigger?secret=YOUR_SECRET"
Confirm alerts land in both channels. Set POLL_HOURS back to "24" and redeploy.
| Resource | Details | Monthly Cost |
|---|---|---|
| Cloudflare Workers | 100k requests/day free | $0.00 |
| Cloudflare KV | 100k reads + 1k writes/day free | $0.00 |
| NVD API key | Free from NIST | $0.00 |
| Telegram + Slack | Both free | $0.00 |
| Total | Fits within all free tiers at 1 run/day | $0.00 |
The next build is a CISA KEV Monitor — watching the Known Exploited Vulnerabilities catalog for new additions and cross-referencing against this watchlist. A KEV entry on top of a CRITICAL CVSS score is the signal that demands same-day action. Same Cloudflare Worker pattern, different data source.
I'm also looking at per-product severity thresholds — some products (Ivanti, Citrix) warrant alerting on MEDIUM CVEs given their historical exploitation rate. The src/cpes.ts structure is already set up to support per-entry configuration.