HoneyLabsOpen-source honeypot telemetry. Query-ready.

Blog · 2026-06-17

Most of the CVE-2026-4020 attackers are the same client

Almost every IP we logged exploiting the Gravity SMTP credential bug shares one HTTP fingerprint. Behind it is a Google Cloud fleet of thousands of short-lived instances, disguised by 3,299 rotating user-agents, sweeping more than 36,000 ports for .env files, git configs, credentials, and database dumps.


CVE-2026-4020 looked like the usual scramble. The Gravity SMTP plugin for WordPress shipped a REST endpoint, /wp-json/gravitysmtp/v1/tests/mock-data, whose permission check just returned true. Add ?page=gravitysmtp-settings and any unauthenticated visitor gets back a 365 KB system report with the plugin's SMTP credentials, SendGrid and Mailgun API keys, and DKIM tokens in it. CrowdSec flagged it under active exploitation, logging 412 distinct IPs on the endpoint between May 27 and June 1.

Our sensors logged 566 IPs reaching for it. 561 of them, 99.1 percent, send the same HTTP client fingerprint. What looks like hundreds of separate attackers racing for a fresh credential bug is, almost to the last address, one operation.

Of 566 IPs that hit the CVE-2026-4020 endpoint, 561 (99.1 percent) carry one HTTP fingerprint

one client, 3,299 disguises

The fingerprint is a JA4H hash: ge11nn0500_9af7e0472034. JA4H is built from the shape of an HTTP request, the method, version, and the order and set of headers, not from anything the client sets per request to blend in. Across our data that one hash covers 480,973 requests from 3,158 source IPs in 92 networks and 43 countries, going back to February 19.

Whoever runs it knows that IP and user-agent are the two fields defenders filter on, so they burned both. The 3,158 IPs sit in 92 different networks so an address blocklist never bites. The requests carry 3,299 different user-agent strings: a 2010 BlackBerry 9800, an Android 1.5 T-Mobile G1, Knoppix, SeaMonkey 2.0.12, a decade of dead browsers picked at random per request. No real fleet of devices looks like that. Under every one of those disguises is the same JA4H. The user-agent is the part they rotate; the handshake is the part they cannot.

what it collects

This is not a vulnerability scanner. Sort the 904 paths it requests and there is no exploit, shell command, or login brute-force near the top. Roughly three-quarters of its requests name a specific secret, key, or config file:

Breakdown of the 480,973 requests by category: .env files 26 percent, framework and config endpoints 23.9 percent, other recon 14.6 percent, root probe 11.5 percent, credential and cloud-key files 8.4 percent, .git exposure 8.2 percent, backups 7.5 percent. No exploits in the set.

CVE-2026-4020 is the newest line in that list. The operation does not treat it as a CVE; it treats it as one more file that returns a credential. When the next "unauthenticated information disclosure" bug ships, it gets appended and swept on the following pass. That is why a week-old CVE already had hundreds of source IPs on it: the collector was running before the bug existed.

rented by the day on someone else's cloud

Eighty-seven percent of the traffic, 419,931 requests from 2,776 of the IPs, comes from one network: Google Cloud, AS396982. The addresses resolve to generic *.bc.googleusercontent.com instances across at least ten countries, heaviest in the US (1,001 IPs) but also Germany, Canada, Belgium, India, the Netherlands, the UK, Australia, Hong Kong, and Brazil. This is not a botnet of compromised home routers. It is a fleet booted on a hyperscaler, on a paid or stolen account.

It mostly idled at a few dozen source IPs a day from February into early June, with the odd small bump, then surged. On June 14 alone the fingerprint came from 1,799 IPs, 1,779 of them on Google Cloud, each working through up to 590 of the same paths. Across June 14 and 15 it ran from 2,443 distinct instances and produced about 374,000 of the fingerprint's 481,000 lifetime requests. By June 16 it was gone. Boot the fleet, sweep for two days, shut it down.

Distinct source IPs per day for the fingerprint from February to June: a flat baseline of a few dozen, then a wall on June 14 and 15 reaching 1,799 in a single day

It also does not stop at web ports. The same fingerprint touched more than 36,000 destination ports, trying its secret-file wordlist against anything that might answer HTTP. The port list is a tour of developer infrastructure: Docker (2375, 2376), etcd (2379, 2380), Kubernetes (6443), MongoDB (27017), Postgres (5432), Elasticsearch (9200), Kibana (5601), CouchDB (5984), RabbitMQ (15672), Neo4j (7687), and, 4,128 times, the Ollama API on 11434. Anywhere a service got left exposed, it wants the environment block behind it.

why one bug looked like many attackers

A distinct-IP count, ours included, measures how many hosts an operation is renting, not how many operations there are. Take our own 566: strip the disguises with a fingerprint and it collapses to one operation that has kept a secrets wordlist current since at least February and adds each new disclosure bug to it. CrowdSec, watching from a separate sensor network, logged 412 of these IPs over a narrower window. Two vantage points, two counts, the same campaign. The fingerprint is the part that shows one hand is behind it.

It is the bulk-collection end of something other teams are seeing from their own vantage points. The DFIR Report documented the Bissa scanner collecting 30,000 distinct .env files in eleven days in April and shipping them to cloud storage. Google's H1 2026 Threat Horizons report puts identity compromise under 83 percent of cloud intrusions, much of it seeded by exposed secrets like these. This fingerprint is what the front of that supply chain looks like up close: one disposable, cloud-rented harvester.

what to take from it

If you run the targets, the fix that lasts is to not serve the files. Keep .env, .git, actuator endpoints, profilers, and database dumps off anything internet-facing, and rotate any secret a 365 KB Gravity SMTP report would have leaked, because if you were exposed during that June window it was almost certainly read. Updating to Gravity SMTP 2.1.5 shuts one door and leaves the rest of the wordlist alone.

If you run the defenses, an IP blocklist was never going to hold here, and neither was a user-agent rule, because the operator treats both as throwaway. The one thing it could not cheaply change was the shape of its own client. A single JA4H hash turned 566 anonymous addresses into one operation you can name and track. That is where the noise actually separates.