Weekly Digest by Email
Follow CVEs and packages and receive one email a week about what changed for them. The digest is sent from notify@vulnpatch.dev on Mondays at 13:00 UTC, and only when something changed: a quiet week sends nothing. The pages for people are at cve.vulnpatch.dev/notify; this page describes the API behind them.
What can be followed
| Kind | Key | What the digest reports |
|---|---|---|
cve | A CVE id, such as CVE-2024-3094 | Added to CISA KEV; EPSS rises by 0.1 or more; a fix version first stated; the record's state changes; its CVSS score is revised; a nixpkgs security issue referencing it opens or closes |
package | A package name as OSV spells it, optionally with an ecosystem | Advisories that newly name the package, in every ecosystem or the one given |
A subscription can follow up to 25 things.
How a change is detected
There is no event log. Each follow keeps a reading, taken the last time it was checked, and the digest is the difference between that reading and one taken now. The reading advances only after the digest is sent, so a send that fails reports the same change the following week rather than losing it, and a run that repeats reports nothing twice.
A reading that cannot be taken is not a reading. The follow is listed in the digest as unchecked, with the reason, and its stored reading is left where it was. A source the dossier could not reach (KEV, EPSS, nixpkgs) keeps that field's previous value, so an outage neither reports a change nor hides the next one.
Subscribing
POST /api/v1/notify/subscribe
Content-Type: application/json
{
"email": "you@example.org",
"follows": [
{ "kind": "cve", "key": "CVE-2024-3094" },
{ "kind": "package", "key": "openssl" },
{ "kind": "package", "key": "lodash", "ecosystem": "npm" }
]
}A confirmation email is sent to the address. Nothing is followed and nothing else is sent until the link in it is opened (double opt-in); the link works once and for 48 hours.
An address that already receives the digest is not sent a confirmation, since one carrying new follows would let whoever typed the address change what its owner receives. It is sent a link to its manage page instead, and the request's follows go nowhere; the owner adds follows from that page, which only their own link reaches.
The response is identical for a new, a pending, an already subscribed and a limited address, so the endpoint cannot be used to learn which an address is. Each address is sent at most one email an hour and three a day by this endpoint, counted under a hash of the address; past that nothing is sent and the answer does not change. Each client is limited to a few requests a day, an IPv6 client counting by its /64. A deployment that cannot send mail answers 503 and stores nothing.
Confirming
POST /api/v1/notify/confirm/{token}Opens the confirmation link. The response carries the subscription and its linkToken, the capability the manage and unsubscribe pages use. Every digest carries the same token in its footer links.
Managing a subscription
All of these take the link token and answer with the subscription: its status, what it follows, and when the last digest went out. The address is returned masked, as the first character and the domain.
GET /api/v1/notify/subscription/{token} what the address follows
POST /api/v1/notify/follows/{token} replace the follows ({ "follows": [...] })
POST /api/v1/notify/unsubscribe/{token} stop the digest at once
POST /api/v1/notify/resubscribe/{token} undo an unsubscribe, within 30 days
POST /api/v1/notify/delete/{token} delete everything held for the addressUnsubscribing in one click
Every digest carries List-Unsubscribe and List-Unsubscribe-Post: List-Unsubscribe=One-Click headers (RFC 8058), naming POST /api/v1/notify/unsubscribe/{token}, so a mail client's own unsubscribe button works without opening a page. The form body the client sends is ignored: the token is the request. The footer link lands on a page that is already unsubscribed on arrival and offers the undo below the confirmation, never in its place.
An unsubscribed address is kept for 30 days so the undo works, then forgotten. Deleting removes the subscription, its stored readings and the address at once.
What is stored
The address, the follows, and the last reading for each follow. Nothing else: no open or click tracking, no preferences beyond the follows. The privacy statement says the same in plain words.
Errors
| Status | Meaning |
|---|---|
400 | The address is not one, or a follow is malformed. Nothing was stored. |
404 | No subscription is reachable through this token: never issued, expired, or the address has been forgotten. |
409 | Undo asked for a subscription that was not unsubscribed. |
429 | Rate limited. Honour Retry-After. |
502 | The confirmation email could not be sent. Nothing takes effect. |
503 | Email subscriptions are not available on this deployment. |