A security advisory only helps if you can still take the fix. I built eol.watch so an end-of-life date reaches you with time to plan the upgrade. Where that tracking already exists, it usually lands too late, and the upgrade shows up as an unplanned priority nobody wants to own.

October was a clean example. That month, Node.js published security releases for the versions it still maintains. The one that spread is CVE-2026-111497. NVD scores it 9.2, critical. The writeups call it Node2Shell, and also HTTP2Shell. Node.js rates the issue high: a flaw in the Brotli decoder bundled with Node, where malformed compressed input can write past an internal buffer. An application that decompresses Brotli data an attacker supplied can crash, leak process memory, or run code.
The fixes went only to versions Node.js still maintains. The announcement says end-of-life versions are always affected when a security release occurs. Node 20 and 18 got no release for this. On a supported version, the response is a patch. On older versions, it is a major upgrade, with breaking changes you would want more time to digest.
Step zero is being able to take the fix
The stream of vulnerability reports this year has a precondition that rarely makes the headline. Before the score, before the exploit chatter, before the Friday thread asking whether it is in our environment: if a fix exists, can we absorb it?
On a supported release, the answer is a change window. You take the patch, you test it, you roll it. The work is real, and it has an edge. The vendor already produced a fix for the version you run.
Past end of life, that option is gone. There is nothing to apply. What you get instead is an unplanned priority: change the dependency now, on a release the tests have already covered. You were going to have to move eventually. You are now doing it when a dependency change is the risky move, and the person who makes it typically owns whatever breaks.
Scanners, SBOMs, and patch SLAs sit on top of that precondition. They find the issue and record when it is closed, which only works if the version you run still receives fixes. Step zero is running a version that does.
The date was public. The urgency was not.
End-of-life dates are often published years ahead. Kubernetes, Node.js, Postgres, the distro under the cluster, the framework an app was generated with: the vendor put the calendar in the open.
We often already track end of life on dependencies. Plenty of enterprises have some version of that: a dependency scan, or someone watching release notes. The signal is real, and a lot of the time it lands too late in the cycle to do anything about it. By the time a dependency scan or a pipeline check says the version is eol, that version has already been validated for a release that has natural pressure to ship now.
Nobody wants to update a dependency at that point. It can break things. It adds risk the team has already signed off on. Across teams, the person who changes it becomes the owner, because they "broke it." Late in a release, that change is often treated as too risky to attempt. So the version stays, and the next advisory finds you are still on it.
The version was current when it went into the build. Its end date was already published. It got old by staying. A major jump planned across a quarter is a project, with time to read the breaking changes and time to test them before anyone has to own the fallout. The same jump, forced because your version will never receive the fix, skips that.
If the lifecycle date was already the deadline, the CVE arrives while you are still on a version that receives fixes. The next version is already chosen. The finding is then simply a patch, not a new project.
A calendar for the stack I actually run
I am bad at remembering which things I run are quietly aging out, especially for personal projects. A spreadsheet might be where this ends up, and it stays right only if someone keeps editing it. A calendar reminder is the same problem with more setup: one event per product, pinned to the date you knew that day. Vendors move those dates, often enough that last quarter's row or reminder is already wrong. Opening endoflife.date when I happen to think of it is the habit that fails on the week I am busy.
eol.watch follows that dataset. You subscribe to the products you actually run, and it sends a reminder when a date is getting close: as far out as a year, then six months, three months, a month, a week, and the day it happens. Email, or a webhook into the chat channel you already watch.
The early reminders are the point. A year out, the upgrade can go on a roadmap. A week out, it is a reminder that the roadmap slipped. The day of, with no earlier warning, is how a lifecycle date turns into the week Node just handed everyone still running 20 or 18.
That is the shift-left. The scan in the pipeline still matters. It tells you what you are about to ship. A reminder a year before end of life gives you time to prioritize the upgrade, before that version is locked into the next releases.
Keeping a pulse that early is what makes the later check boring.
You can track a small personal stack for free. The longer look-ahead is there when the list, or the planning horizon, outgrows that.
It watches lifecycle dates. A dependency report already covers what is in a build. That version was current when it got there. It aged by staying. The reminder comes before anyone notices that in the report.
Learn the date before the advisory does
For example, teams still on Node.js 20 or 18 did not get a quiet reminder when security support ended. They got an October release whose patches do not apply to them. The upgrade was already a known project. The advisory is what turned it into someone's unplanned priority.
The vulnerability reports are going to keep coming. The part I can control beforehand is smaller than it sounds. When the next one names something I run, I want to be in the easy position to simply take in the fix.