Proxmox Auth Bypass CVE-2023-54391: Detect and Fix It

CVE-2023-54391 scores 9.8 and logs an attacker in as root@pam with no password on Proxmox VE 7.x. Check libpve-access-control and close it today.

Proxmox PulseProxmox Pulse
8 min read
Vault door slightly ajar with light leaking through, symbolizing an authentication bypass.

One Parameter, No Password, root@pam

On 1 September 2026, Proxmox published advisory PSA-2026-00043-1 and NVD published CVE-2023-54391: a pre-authentication bypass in libpve-access-control that lets an unauthenticated attacker log in as any existing enabled user - including root@pam - by supplying an arbitrary value for the tfa-challenge parameter on the API login endpoint.

CVSS v3.1 scores it 9.8 CRITICAL (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H), classified as CWE-304, Missing Critical Step in Authentication. VulnCheck, which published the advisory, scored it 9.3 on CVSS v4 and lists it in the VulnCheck KEV catalogue.

The awkward part is the CVE year. This was fixed in libpve-access-control 8.0.4 in July 2023. The identifier is new; the exposure window is three years wide, and every affected release is now end of life.

Key Takeaways

  • Affected: Proxmox VE 7.0 through 7.4 and the initial 8.0 release - libpve-access-control 7.0-7 up to (not including) 8.0.4.
  • Fixed: libpve-access-control 8.0.4, July 2023. Current 8.x and 9.x nodes are not affected.
  • The mechanism: password verification is skipped when a tfa-challenge parameter is present, and its value was not validated for users with no configured second factor.
  • TFA is the only mitigating control, and only for accounts that actually have it enabled - which rarely includes service accounts.
  • Every affected release is EOL, so remediation is an upgrade, not a patch, for anyone still on 7.x.

How the Bypass Works

Proxmox authenticates against POST /api2/json/access/ticket. In the normal two-factor flow the client posts credentials, receives a TFA challenge, and posts back with a tfa-challenge parameter carrying that challenge plus the second factor. Because the second leg of that flow has already proved the password, the handler treats the presence of tfa-challenge as evidence the password step is done.

The bug is that the parameter's value was never validated for a user who has no second factor configured. Present the parameter, skip the password check, receive a ticket for whichever user you named. No credentials, no prior access, no interaction.

Two consequences follow that are worth stating plainly. First, a ticket for root@pam is total control of the host - every VM, every container, every disk on it, and via /etc/pve the cluster filesystem shared with the other nodes. Second, an account with a configured second factor is not vulnerable, because the challenge validation path it takes is the one that works. That is why enabling TFA broadly is genuinely protective here, and why it protects almost nobody in practice: the accounts that get TFA are the human ones, and the accounts that sit forgotten in /etc/pve/user.cfg are not.

Upstream fixed it across two commits in pve-access-control (032e7d6d and 0f3d14d6), which validate the challenge ticket rather than trusting its presence.

Are You Exposed? Four Checks

Run these on every node. Cluster membership does not imply identical package versions - nodes drift, especially ones added later or restored from an old image.

1. The package version.

pveversion -v | grep libpve-access-control
libpve-access-control: 8.0.4

Below 8.0.4 is vulnerable. Full stop. If you would rather ask dpkg directly:

dpkg-query -W -f='${Package} ${Version} ${Status}\n' libpve-access-control

2. Who can reach the login endpoint.

ss -lntp | grep 8006

pveproxy binds 0.0.0.0:8006 by default. The question is what your firewall does in front of it. Test from outside the management network - not from a jump host that is already trusted:

curl -sk -o /dev/null -w '%{http_code}\n' https://<node-ip>:8006/api2/json/version

A management interface that answers from a general-purpose VLAN is the precondition that turns this from "bad" into "already happened." Our guide to VLAN segmentation with Proxmox bridges and firewall rules covers putting 8006 behind a boundary properly.

3. The access log.

pveproxy logs every request in combined format. Look at what has been hitting the ticket endpoint:

grep 'POST /api2/json/access/ticket' /var/log/pveproxy/access.log*

On a healthy cluster the client addresses are your admin workstations and your automation hosts. Anything else deserves an explanation. Correlate with the successful-authentication lines the daemon writes:

journalctl -u pvedaemon --since '90 days ago' | grep 'successful auth'

You are looking for successful authentications - especially for root@pam - from addresses that do not appear in your normal administrative pattern, and for successes that are not preceded by the usual authentication chatter. Log retention will probably defeat you here; three years is well beyond default rotation. Absence of evidence is genuinely not evidence of absence on this one.

4. The user database.

cat /etc/pve/user.cfg

Review every enabled user and every API token. An attacker who obtained a root@pam ticket had no need to leave one behind, but persistence is cheap and people take it. Our walkthrough on securing Proxmox API tokens is a useful checklist for what a healthy token inventory looks like.

Remediation

If you are on 8.x or 9.x

You are almost certainly already patched, since 8.0.4 shipped in July 2023. Confirm rather than assume, then move on:

apt update && apt full-upgrade
pveversion -v | grep libpve-access-control

If you are on 7.x

There is no version of this that ends with you staying on 7.x. That line went end of life in July 2024, and the 8.x line followed on 31 August 2026. Proxmox has provided a stop-gap that validates the tfa-challenge ticket for affected end-of-life installs, and you should apply it today - but treat it as the thing that buys you a maintenance window, not the fix.

The order of operations:

  1. Restrict TCP 8006 immediately to a management VLAN or VPN. This is the control that actually stops an unauthenticated internet attacker while you plan.
  2. Apply the vendor stop-gap from the Proxmox security advisories thread.
  3. Enable TFA on every account that has a human behind it, which protects those accounts against exactly this class of flaw.
  4. Plan the upgrade. Going 7.x to current is two hops through 8.x; our Proxmox VE 8 to 9 upgrade guide covers the second one.

If the node was internet-reachable while unpatched

Rotate as though it were compromised: root@pam and every other local password, all API tokens, SSH host keys and authorized keys, and any credential a VM or container on that host had access to. Then check for the boring persistence - unexpected users in /etc/pve/user.cfg, cron entries, and modified hook scripts.

Hardening the Login Endpoint Itself

Patching this CVE fixes this CVE. The management API is going to keep attracting authentication bugs, so it is worth spending the same maintenance window narrowing the endpoint permanently.

Bind it somewhere sensible. pveproxy listens on every interface by default. If your node has a dedicated management NIC, say so in /etc/default/pveproxy:

LISTEN_IP="10.20.0.11"

Then restrict who may talk to it, in the same file:

ALLOW_FROM="10.20.0.0/24,10.20.5.7"
DENY_FROM="all"
POLICY="allow"

Restart the proxy and confirm you did not just lock yourself out - keep a console session open while you do this:

systemctl restart pveproxy
ss -lntp | grep 8006

Enforce a second factor at the realm. Because this bug specifically spared accounts with a configured second factor, realm-wide TFA enforcement would have blunted it entirely. Configure it under Datacenter -> Permissions -> Two Factor, and audit which accounts still lack it - that list is usually longer than expected and is almost entirely service accounts. Our TOTP and WebAuthn setup walkthrough covers enrolling them without breaking automation.

Rate-limit the guessing. The Proxmox firewall and fail2ban together turn credential attacks against 8006 into noise rather than a working attack surface; see hardening the Proxmox firewall with fail2ban and SSH for the jail configuration that reads pveproxy authentication failures.

None of these would have stopped a valid-looking ticket request from an allowed source. All of them shrink the set of people who get to try.

Reading the Threat Signals Honestly

The signals on this CVE point in different directions, and it is worth being straight about that rather than picking whichever one supports the conclusion you already wanted.

Pointing toward urgency: an unauthenticated bypass to root on a management API, a 9.8 CVSS, inclusion in the VulnCheck KEV catalogue, public technical write-ups, and a vendor advisory urgent enough to ship a stop-gap for end-of-life releases.

Pointing the other way: the EPSS score sat at roughly 0.5 percent at the 39th percentile in early September, and no public proof-of-concept is catalogued in the main CVE databases. That is a modest predicted-exploitation signal for a 9.8.

The reconciliation is that EPSS models internet-wide exploitation volume, and Proxmox management interfaces are - correctly - not usually exposed to the internet. The population is small; the consequence per host is total. If you want to watch how those numbers move as more sources report, the CVE-2023-54391 entry on CVE Explore tracks the CVSS breakdown, EPSS history, KEV status and the upstream patch references in one place, which is a faster read than reconciling NVD against a vendor advisory by hand.

Either way, the remediation is unchanged, cheap, and you were going to have to leave 7.x anyway.

Conclusion

Run pveversion -v | grep libpve-access-control on every node. If it is below 8.0.4, that node has been accepting password-free logins as root@pam for anyone who could reach port 8006 since 2023.

Current 8.x and 9.x installs are fine and have been for years. Everything still on 7.x needs its API port restricted today, the vendor stop-gap applied this week, and a genuine upgrade path on the calendar - because the next advisory against an end-of-life release will not come with a stop-gap at all.

Share
Proxmox Pulse

Written by

Proxmox Pulse

Sysadmin-driven guides for getting the most out of Proxmox VE in production and homelab environments.

Related Articles

View all →