HoneyLabs

Blog · 2026-07-23

The probe that came 17 days before the CVE

A single-purpose IP checked cPanel login path 17 days before the vendor advisory for CVE-2026-41940. How we measure pre-publication probing across 30M+ probes without fooling ourselves, and the three actors that survive the checks.


On April 11 at 08:08 UTC, one of our honeypots received a request for /login/?login_only=1 on port 2087 from 85[.]122[.]114[.]177, an address on Alexhost (AS200019). Port 2087 is cPanel's WHM interface over TLS, not a port a broad web sweep bothers with, and that path is its login page. The address sent 16 of these requests over three days and then went quiet. It has never requested anything else from us, not on 2087 and not on any other port, not before and not since.

Seventeen days later, on April 28, cPanel published an advisory for CVE-2026-41940: a CVSS 9.8 authentication bypass in exactly that login flow. Rapid7 and Censys wrote it up within days, and Picus estimated around 1.5 million exposed servers. NVD catalogued the CVE on April 29. On April 30 the crowd showed up: twelve source IPs on that path in a single day, and 554 distinct addresses since.

Probes per day on the cPanel login path: a small cluster of blue bars on April 11 to 13, silence, then a wall of gray bars from April 30

TL;DR: some addresses probe a CVE's exact exploit path weeks before an NVD entry or any public exploit tooling exists. We went through 30 million honeypot probes looking for them, built four checks to kill the false positives, and ended up with three actors we are confident about. The method and the live table are below.

How we noticed

We tag incoming probes against CVE exploit signatures, 1,697 of them at the time of writing, and every CVE page on the site draws a daily timeline of matching probes. While reviewing those timelines we kept seeing the same shape: a small trickle of matching requests before the CVE's publication date, and a flood after it. Our first thought was that the matcher was too loose. Our second was that we were measuring something wrong. Both turned out to be true most of the time, and this feature is about the handful of cases where they weren't.

CVE-2026-5073 taught us the most. Our first scoring pass flagged it as the perfect find: probing started well before publication, it came from 809 distinct IPs, and the naive score came out at the maximum. It was also completely wrong. The probing "started" on the exact day our sensor coverage started. We had joined a campaign that was already running and mistaken our own turn-on date for the beginning of the campaign. That mistake is now a permanent filter, and it removes more CVEs than any other check we run.

What counts as public

NVD's publication date often lags the real public signal, sometimes by weeks. For a lot of CVEs there is an exploit template in the nuclei-templates repository before NVD dates the entry, and once a template is public, traffic that matches it is expected. So we mine the first commit date of each CVE's template from the repository's git history and use whichever is earlier, the NVD date or the template date, as the reference:

t_ref(c)    = min( t_nvd(c), t_tooling(c) )
lead(a, c)  = t_ref(c) - t_first(a, c)     # a's first probe matching c's signature
breadth(a)  = |{ distinct url_paths requested by a, across all sensors }|

flag(a, c)  = lead(a, c) > 0
              and breadth(a) <= 50
              and a not in known_scanners
              and t_first(a, c) - t_coverage_start >= 3 days

How a lead is measured: from the first matching probe to the earlier of the NVD entry and the first exploit-template commit

The inputs are limited on purpose: our own honeypot traffic (UTC timestamps, request lines logged verbatim), the NVD API for publication dates and CVSS, the nuclei-templates git history for tooling dates, and a list of known research scanners built from reverse DNS and network ownership. At no point do we depend on a third party's claim about who probed what when. Every timestamp in the analysis is one we recorded ourselves.

The anchor is still not perfect. A vendor advisory or a patch diff can be public before both of our dates, and with a better reference a lead gets shorter. The cPanel case above is 18 days when measured against NVD and 17 when measured against the vendor advisory. Treat every lead in this post as an upper bound.

The four checks

Any honeypot operator can reproduce the opening of this post: take a CVE's exploit path, grep old traffic for it, and find a hit that predates the CVE. We built exactly that naive version first, and it was wrong in four different ways. What is live today is what remained after we fixed them.

The first problem is the signature. A pattern like / matches every request ever recorded, and at one point a single overbroad pattern tagged 65 CVEs at the same time. Endpoints like /.env and the common admin panels have been recon staples for a decade, long before the CVEs that now reference them. Only signatures that are specific enough to discriminate, at medium confidence or better, are allowed to attribute anything.

The second is the clock, described above: measuring against NVD alone makes the numbers look better than they are, so the reference is the earliest public signal we can document.

The third is the edge of our own data. Our coverage has a start date, and a "lead" whose first probe falls within three days of that start most likely belongs to a campaign that was already underway when our window opened. Verdicts like that are dropped. This is the CVE-2026-5073 lesson from earlier, made permanent.

The fourth is the crowd. An IP that requests 1,600 different paths will "predict" every CVE whose signature happens to be a common endpoint. We drop known scanners, and we drop any IP that touched 50 or more distinct paths across our telemetry; the fleets we exclude this way sit between 300 and 1,600 paths each. What remains is what we call a focused actor: an address whose interest was narrow.

Run everything we have recorded through those four checks and the numbers collapse:

Funnel from 1,697 tracked signatures to 3 CVEs with a focused early actor

Of 1,697 tracked signatures, three currently trace to a focused early actor. That is 0.18%, and we prefer it that way: a looser filter would fill the table with rows nobody can act on.

The three that survive

Source IP Network CVE First probe Days early Paths ever hit
85[.]122[.]114[.]177 Alexhost, RO CVE-2026-41940 Apr 11 18 1
193[.]34[.]212[.]9 MEVSPACE, PL CVE-2026-33626 Feb 23 56 13
185[.]177[.]72[.]138 Bucklog SARL, FR CVE-2026-8181 Mar 18 57 35

The cPanel case is the cleanest of the three: one path, 16 requests, 17 days ahead of the vendor advisory for a bug that went into mass exploitation the week it was published. We do not know what those 16 requests carried. We log the request line, and a GET to a login page is compatible with an exploit attempt but just as compatible with someone checking which hosts run cPanel. None of the pre-publication traffic for any of the ten flagged CVEs is exploit-shaped: no injection markers, no exploit query strings. What we do know is which door the address checked, that it never checked any other door in anything we have recorded from it, and that it did this 17 days before the vendor said anything in public.

193[.]34[.]212[.]9 requested /v1/chat/completions on port 443 on February 23, 56 days before NVD published CVE-2026-33626, a server-side request forgery in LMDeploy's vision module. This row comes with a caveat: standard HTTPS and a path that is the default endpoint of every OpenAI-compatible LLM API, and scanning for exposed LLM endpoints was a genre of its own before this CVE existed. The lead is real, but whether it reflects this specific CVE or a general interest in exposed models is a judgement call. That is why the row links to the raw evidence instead of drawing the conclusion for you.

185[.]177[.]72[.]138 hit /wp-json/wp/v2/users on port 8087, a non-standard port for a WordPress site, on March 18, 57 days before CVE-2026-8181, an authentication bypass in the Burst Statistics WordPress plugin that involves that endpoint. Here the caveat applies with more force, because WordPress user enumeration is older than the CVE by a decade. We also know this network: the 185[.]177[.]72[.]0/24 block belongs to the operation that stuffs 127[.]0[.]0[.]1 into every client-IP header its tooling knows. An established recon operation arriving early at a recon endpoint is the least surprising row in the table. It stays because it passed every check, and deciding that it is uninteresting is exactly the kind of judgement the table is meant to support.

About the data

Only CVEs published after our sensor coverage began can be assessed at all. That is 86 CVEs today. Every CVE published from now on becomes assessable the day it gets a date, and the scan recomputes every hour, so the table grows on its own.

Our sensors sit on untargeted address space, which has a consequence worth being explicit about: a researcher testing an unpublished detection looks identical to an attacker with early access to a bug. We cannot tell those apart, and the table does not pretend to. It attaches the evidence, first-seen timestamps, per-day timelines and the exact request lines, and leaves the interpretation to you.

Read the three rows as a floor and not a census. An actor that probes a sensor we don't have is an actor we don't see. If you would rather not check the table by hand waiting for row four, an account can pull it as a feed for a firewall or SIEM, or send you an email when a new actor is flagged.

Conclusion

Publishing this cuts both ways. The table shows defenders which addresses were early, and it shows the operator of such an address that they were noticed. The way to avoid the flag is to scan broadly and blend into the crowd, which costs exactly the quietness that made early probing attractive. That trade works in the defender's favour, so we are fine with it.

The more general lesson from building this is about measurement. Probing before disclosure is observable, but only if you were recording before the disclosure happened, and only if you are strict about what "before" means. Most of the work in this feature went into not fooling ourselves: better reference dates, coverage guards, scanner filters. If you run sensors yourself, keep them simple, log the request lines verbatim, and date your findings against the earliest public signal you can prove.

If an address in the table overlaps with traffic you are seeing, we would like to hear about it: info@honeylabs.net.

Indicators in this post are obfuscated following draft-grimminck-safe-ioc-sharing, so they stay readable without being clickable into an attacker's infrastructure. The links on them point at our own reports.

New research, by email

Get new HoneyLabs research by email as it publishes: write-ups like this one, plus the threat reports on which ports moved, which KEV and recent CVEs are being probed in the wild, and the attack paths worth grepping your own logs for. Here is a recent threat report.

Double opt-in: we send one confirmation email and nothing else until you click it. Unsubscribe in one click, any time.