When a big CVE lands, the question that reaches a systems team is always the same: "are we affected?". And so is the answer that usually closes the thread: "the scanner says no". Today we went to look at what the scanner actually has on the table to be able to say that about this particular CVE. The short answer is: nothing.
We are talking about CVE-2023-54391, the Proxmox VE authentication flaw we wrote about when the advisory came out. That post was about the hole itself: at the API login endpoint, sending any value in the tfa-challenge parameter skips password verification entirely for any account without a second factor, root@pam included. This one is about something else: why, three weeks later, it is still hard to answer whether you have it or not.
What the record returns, field by field
A vulnerability scanner knows nothing about Proxmox. It knows how to read a list of affected versions and compare it against what it finds on your machine. That list almost always comes from two places: the NVD record and GitHub's advisory database. This morning we pulled both through their APIs. These are the fields that matter.
- →In NVD,
configurationsis null. There is no CPE applicability statement: not a single product-and-version identifier to match against what is seen on your network. - →
vulnStatusis "Deferred". That is the label NVD uses to say it will not enrich this record. The gap above is not a backlog: it is the intended end state. - →In GitHub, advisory GHSA-m457-grcf-698x exists, says critical and carries both scores — 9.8 on CVSS 3.1 and 9.3 on CVSS 4.0 — but its
vulnerabilitiesfield is an empty array. The why is two fields down:type: "unreviewed"andgithub_reviewed_at: null. Nobody at GitHub has been through to fill in the range, and without review there is no range. - →All there is structurally comes from the CVE's assigner, which is not Proxmox:
defaultStatus"unaffected", and two affected entries,{version: "7.0", lessThanOrEqual: "7.4"}and{version: "8.0"}, both withversionType: "custom".
That last field is what breaks the automated check. versionType: "custom" means, literally, that no comparison scheme is declared. A tool reads "affected up to and including 7.4", finds a node introducing itself as pve-manager/7.4-17, and has to decide on its own. Under Debian version ordering, which is what applies to a .deb, 7.4-17 is revision 17 of upstream 7.4 and sorts above a bare "7.4": outside the range, node green. Under semver-style rules the opposite comes out, because there the suffix lowers precedence and the node would be in scope. Two reasonable tools, two opposite verdicts on the same machine. That is precisely what not declaring the scheme means.
And there are two more silences in the same record. The first we already checked on 4 September: this CVE was not in CISA's KEV catalogue. We downloaded it again today, version 2026.09.22, and it is still not there; nor is any other Proxmox entry in the whole catalogue. The new part is not the absence, it is that it has lasted three weeks. The second sits inside the NVD record itself: an SSVC block signed by "CISA Coordinator" on 2 September marking automatable: yes and technicalImpact: total, and at the same time exploitation: none. Add the EPSS GitHub returns, 1.75% at the 76.8th percentile, and you have a 9.8 that every automated traffic light rates amber.
The patch that does exist for the 7 branch
The fix is not in the hypervisor, it is in the libpve-access-control package, which is numbered in a different series; and on the 7 branch no version carries it, because the code was closed inside 8.0.4 and Proxmox acknowledges in its advisory that at the time "it was therefore not recognized as a candidate for a backport to the PVE 7 branch". We covered that earlier this month, and it takes two minutes to verify: the stable-7 branch of the public pve-access-control repository ends at 7.4.3, dated February 2024, and the two fix commits are not in it.
What almost nobody has covered, and it is the useful part, is that in that same advisory Proxmox published a patch for those who cannot migrate yet. It is a short script that adds the missing validation: from then on every tfa-challenge has to be a valid, signed ticket that an attacker cannot forge, and neither normal password logins nor two-factor logins stop working. Applying it by hand is not migrating, and the node is still out of support with everything that drags along. But it closes this particular door today, and the migration then gets planned cold rather than at two in the morning.
Eleven hundred machines, twelve hypervisors, seventeen days
All of the above would be a metadata argument if it did not come with a bill. It does, and it is published. A Finnish hosting provider, Pulsed Media, published a notice on 20 September explaining that an automated cryptocurrency-mining campaign had obtained root on twelve of its Proxmox VE hypervisors. The way in was this CVE. The window runs from 31 August to 17 September, the day they themselves detected and contained it: seventeen days. And they give a figure we have not seen anywhere else: "Roughly eleven hundred machines worldwide were in this campaign".
That they published it in that much detail is more than most do, and it is why this post carries data instead of guesses. Their notice lists what they did: they removed the malware and every persistence mechanism they identified, closed the way in on all twelve hosts, restored the logging the attacker had switched off, rotated host access passwords and restricted the Proxmox management interface to their own networks. Their contact, billing and payment systems were not compromised.
That "restored the logging" is worth reading slowly: they switched the mechanism back on, they did not recover what the attacker had already deleted. Out of that comes the sentence we find the most important in the whole notice. They found no sign that customer data had been read, copied or modified, and then they write, verbatim, "the deleted logs mean we cannot prove it either way". Which is why they told the affected customers to treat their data as potentially exposed.
That is the real cost, and it is not the CPU somebody stole from you to mine with. The mining is the noise. The expensive part is the distance between "nothing happened" and "I cannot prove nothing happened", because the second one is what you say in front of a customer, an insurer, or whoever is asking about Article 33. That distance was not decided by the attacker on the day of the incident; it was decided months earlier, by whoever let the logs live only on the machine that generates them. It is the same pattern we wrote about from another angle: patching the kernel means rebooting, and rebooting erases the evidence.
Four checks, ten minutes per node
- Ask about the package, not the product.
dpkg-query -W -f '${Version}\n' libpve-access-controlon each node, which is the command the advisory itself recommends (pveversion -vworks too and lists everything else while it is at it). The affected range is exact: >= 7.0-7 and < 8.0.4. Do not check whether it is "series 7": check whether it falls inside that range. A node on 8.0.2 is also in scope, and that is exactly the one that slips through the mental rule of "we are already on 8". - Check who can reach the API. The attack requires reaching the management port, 8006 by default.
ss -lntp | grep 8006tells you which interface it listens on; your firewall tells you where it can be reached from. If the answer to the second one is "from the internet", you have a job for today regardless of version. - Count the accounts with no second factor. The flaw does not affect users who have a second factor configured, but that protection is per account, not per node: one old account without TOTP is enough to make the whole cluster reachable. The configuration lives in
/etc/pve/priv/tfa.cfgand in the UI it sits under Datacenter → Permissions → Two Factor. Compare it against the user list, not the administrator list. - Check that your logs leave the host. This one is not a check for this CVE: it is the one that decides whether you will ever be able to answer what happened. If a node's
auth.logexists only on that node, your ability to prove anything depends on the attacker not touching it, and we have already seen above what they start with.
For a twenty-node estate that is one morning, and it produces an inventory that will serve you for the next advisory and the one after that. And if you are going to migrate those nodes anyway, the access and firewall decisions are best taken during the migration, not after it: we have them laid out in our Proxmox hardening guide for production.
What we are not going to recommend
- ✗Switching scanners. The next one will read the same two databases and return the same silence. The problem is not the tool, it is the data that is not there.
- ✗Migrating in a rush "because there is a 9.8". A hurried migration breaks more than it fixes. If you cannot migrate this week, apply the patch the vendor published and restrict the management interface to your own networks. That gets done today, with the migration planned for when it suits.
- ✗Calling the cleanup done and moving on. If a host was compromised with root access, "we cleaned it" is a hypothesis. Rebuilding is cheaper than carrying that hypothesis for two years, and certainly cheaper than defending it in front of a customer.
How we set this up
When the preventive control cannot answer — and today, with this CVE, it cannot — what is left is detecting and being able to prove. That is why the managed EDR and detection service we run does not end at the installed agent: telemetry and logs leave the host and are kept outside it, with their own retention, so that wiping them on the machine does not wipe your answer. And behind it there are people on call, because the window between something happening and somebody looking is the variable you genuinely control. Seventeen days is what that window can stretch to; nobody picks it, you inherit it from the rota you have.
"Published" is not "applied", and "it does not show up in the scanner" is not "it does not affect me". The first one we covered with a patch that had been available for 97 days; the second one is this post. They are the same sentence said twice, and both times it costs money for the same reason: the system that warns you is not the system that protects you.
Sources (consulted on 23 Sep 2026): the configurations, vulnStatus and affected fields and the SSVC block we read in the response from the NVD 2.0 API (timestamp 2026-09-23T06:32 UTC); the vulnerabilities: [], the type: "unreviewed" and the EPSS in the GitHub Advisories API; the absence from the catalogue in CISA's KEV, version 2026.09.22. The >= 7.0-7 and < 8.0.4 range, the check command, the patch for those who cannot migrate and the sentence about the backport are in Proxmox's PSA-2026-00043-1; the stable-7 branch can be checked in the public pve-access-control repository. The incident, dates, figures and verbatim quotes are in Pulsed Media's public notice of 20 Sep 2026. What this post does NOT claim: we have not reproduced the attack nor verified any technical indicator of compromise in our own lab, and the eleven-hundred-machine campaign figure comes from that provider, not from an independent source.
Could you prove today what happened on your hypervisors last month?
At everyWAN we have run Proxmox in production for years, with managed detection and logs that leave the host. If you want the inventory of the four checks above across your estate, we will run it and hand it over in writing, whatever it says.
Talk to everyWAN