Skip to content
l5z12Public

About

Monitor latest CVEs published in real time with Telegram & Discord

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Globe Shield icon

CVE Watch

Sends newly published CVEs, and CVEs newly added to CISA's KEV catalog, to Telegram, Discord, or both.

Checks the CVE List and CVE Search every 15 seconds, with NVD recovery every 5 minutes, so new CVEs usually arrive within minutes. Includes unscored CVEs, deduplicates IDs, retries failed deliveries, and edits the alert, without a new notification, when a score is published later. Upstream delays are possible, and a crash after sending can occasionally cause a duplicate.

Deploy with GitHub Actions

Uses the Cloudflare CLI (cf) and Vite. Requires pnpm and a Cloudflare account; pnpm installs the pinned Node.js 24.22 runtime.

  1. Choose your destinations: for Telegram, create a bot with BotFather, give it permission to post, and note the channel username or numeric ID. For Discord, create a webhook under Channel Settings > Integrations.

  2. Install and create the database:

    pnpm install --frozen-lockfile
    pnpm exec cf login
    pnpm exec cf d1 create --name cvewatch-db
  3. Configure GitHub Actions (repository or production environment):

    • Deploy secrets: CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID. The token needs Workers Scripts: Edit and D1: Edit.
    • Destination secrets: TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID, DISCORD_WEBHOOK_URL, or both. Configure at least one destination.
    • Variable: D1_DATABASE_ID, using the returned database ID.
    • Optional secret: NVD_API_KEY.
  4. Push or merge to main. CI checks the code, applies migrations, and deploys with the Worker secrets. Polling starts after cron propagation.

Omit or leave unused destination secrets empty. Disabling a destination pauses its existing queue and stops adding new deliveries for it; queued alerts resume if you re-enable it.

Discord alerts use the project icon hosted at /icon.png. For Telegram, upload public/icon.png as the bot's profile picture through BotFather. Icon attribution and its MIT license are included in NOTICE.

Settings

Config is in cloudflare.config.ts:

Variable Default Purpose
LIVE_POLL_SECONDS 15 Recent-publication polling interval
POLL_INTERVAL_MINUTES 5 NVD recovery interval
INITIAL_LOOKBACK_HOURS 24 Startup history, including KEV additions; set 0 before first run for new ones only
DELIVERY_BATCH_SIZE 4 Messages per channel per run

Development

Run pnpm hooks:install once per clone to enable prek commit hooks. pnpm hooks:check checks all tracked files; CI also runs the file checks.

Use pnpm format to format files with Prettier or pnpm format:check to check them. The commit hook formats staged files; pnpm check verifies formatting in CI.

Copy .dev.vars.example to .dev.vars and add test-channel credentials.

pnpm db:migrate:local
pnpm dev

Trigger the first run from another terminal:

curl "http://localhost:8787/cdn-cgi/local/scheduled?cron=*+*+*+*+*"

This starts recurring alarms and sends real messages. Local NVD recovery needs repeated calls. Stop the dev server to stop activity. pnpm check uses mocked messaging APIs.

When you change how CVE Program records are parsed in a way that alters alerts, increase PARSER_VERSION in src/cve-search.ts. Alerts queued before the deployment are then parsed again before they are sent.

Monitoring

Open /health for a status page. Use /api/health/ for overall status, or /api/health/telegram/ and /api/health/discord/ for each destination. HTTP 200 means healthy, with status warn if the last NVD recovery or KEV poll failed but its data is still fresh, or a destination is stopped; HTTP 503 means unavailable or degraded. Check Cloudflare Worker logs for details.

Emergency stop

To stop alerts at once, run the Emergency stop workflow from the Actions tab with stop, for all destinations or just one. The Worker checks before every message, so at most one more message goes out per destination. Nothing is sent or edited until you run the workflow again with resume. Polling continues while stopped, and queued alerts go out, newest first, after you resume. The workflow uses the deploy secrets and variable, takes effect without a deployment, and shows each destination's state in its summary. From a terminal, with a Cloudflare API token that has D1: Edit:

CLOUDFLARE_API_TOKEN=<token> CLOUDFLARE_ACCOUNT_ID=<account-id> D1_DATABASE_ID=<database-id> node scripts/emergency-stop.mjs stop

Send an existing CVE

Run the Send CVE workflow from the Actions tab and enter a CVE ID. It uses the deploy secrets and variable, waits for the Worker, and fails if the CVE cannot be sent. From a terminal signed in with cf login:

D1_DATABASE_ID=<database-id> pnpm send CVE-2024-3094

The Worker picks up the request within about 15 seconds and sends the CVE List record, using NVD scores when the record has none. The CVE is sent to every enabled destination, even if it was alerted before, and queues behind newer pending alerts. Its message starts with the ID instead of "New CVE". The request is stored in the production database, so this does not work with the local dev server.

License

Apache-2.0. See NOTICE for attribution. CVE data remains subject to the CVE Terms of Use.

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

About

Monitor latest CVEs published in real time with Telegram & Discord

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages