Security · Cloudflare Workers March 2026 Joshua Burnie

Building a CVE Watcher that alerts before your vendor does

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.

Cloudflare Workers NVD API v2 TypeScript Telegram Bot API Slack Block Kit Cloudflare KV

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.

What It Does

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.

telegram · @JoshCVEWatcher_bot · live example
🔴 CRITICAL | CVE-2026-28229
ProductKubernetes
CategoryCloud Native
CVSS v3.19.8 — CRITICAL
VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Published2026-03-11
Argo Workflows is an open source container-native workflow engine for orchestrating parallel jobs on Kubernetes. Prior to 4.0.2 and 3.7.11, Workflow templates endpoints allow any client to retrieve WorkflowTemplates. Any request with Authorization: Bearer nothing token can leak sensitive template content...

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.

How It Works

# Cloudflare Cron — daily at 9am UTC (0 9 * * *) │ ▼ Worker (index.ts) │ ├─► NVD API v2 ──────► 20 keywordSearch queries (700ms apart) │ Filter: CVSS ≥ 7.0 only │ ├─► Cloudflare KV ──► Dedup check (30-day TTL per CVE ID) │ Skip CVEs already seen │ └─► Promise.all([ Telegram Bot API, ─► Summary + individual alerts Slack Webhook ─► Block Kit cards in #security-alerts ])

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.

The Stack

Cloudflare Workers
Serverless runtime. Cron triggers, zero infrastructure.
🗄️
Cloudflare KV
CVE deduplication. 30-day TTL per seen CVE ID.
🔍
NVD API v2
NIST's National Vulnerability Database. Free, authoritative.
✈️
Telegram Bot API
HTML-mode messages with bold, code, and inline links.
💬
Slack Webhooks
Block Kit cards posted to a dedicated security channel.
🔒
Wrangler CLI
Encrypted secret storage, deploys, and live log tailing.

The Watched Products

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.

Network Security
Palo Alto PAN-OSFortinet FortiOSCisco ASACheck Point Gaia OS
VPN / Remote Access
Ivanti Connect SecureCitrix NetScaler ADCF5 BIG-IP APM
Web / TLS
OpenSSLApache HTTP Servernginx
Operating Systems
Linux KernelVMware ESXi
Microsoft
Exchange ServerWindows Server 2022Windows Server 2019
IAM
OktaCyberArk PAS
SIEM
Splunk Enterprise
Cloud Native
KubernetesDocker Engine

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.

Step-by-Step Build

01

Clone the repo and install dependencies

git clone https://github.com/joshuaburnie/cve-watcher
cd cve-watcher && npm install
02

Get a free NVD API key

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.

03

Create the KV namespace

npx wrangler kv namespace create CVE_SEEN

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

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 user ID from @userinfobot.

05

Create your Slack Incoming Webhook

Go to api.slack.com/apps/new → From scratch → Incoming Webhooks → Add webhook to your channel → copy the URL.

06

Upload all secrets

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
07

Deploy

npm run deploy

Confirm output shows KV namespace ID, POLL_HOURS: "24", and schedule: 0 9 * * *.

08

Test end-to-end

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.

Cost

ResourceDetailsMonthly Cost
Cloudflare Workers100k requests/day free$0.00
Cloudflare KV100k reads + 1k writes/day free$0.00
NVD API keyFree from NIST$0.00
Telegram + SlackBoth free$0.00
TotalFits within all free tiers at 1 run/day$0.00

Security

// security layers
  • /trigger endpoint requires a secret query parameter — unauthorized requests return 401
  • All secrets stored encrypted via Wrangler — never in source code or config files
  • NVD API key passed in request header, not URL (per NVD v2 spec)
  • Outbound requests only — no inbound webhooks to spoof or replay
  • KV stores CVE IDs only — no sensitive data persisted

What's Next

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.