
Executive Summary
Proxmox Virtual Environment versions 7.0.0 through 8.0.3 shipped a critical unauthenticated authentication bypass vulnerability that enabled attackers to mint a full root@pam authentication ticket using a single HTTP request without providing a valid password. The vulnerability was fixed in July 2023 as libpve-access-control version 8.0.4, but the fix was released without a CVE number or security advisory, leaving operators of end-of-life systems unaware that their installations were vulnerable for three years. The bypass exploits a chain of three logic failures in the two-factor authentication (TFA) handling code, allowing an attacker to skip password verification entirely and bypass challenge validation.
This analysis reconstructs the vulnerability from the fix patch, demonstrates a working proof-of-concept exploit, explains the underlying root cause, and provides detection rules and mitigation strategies for affected systems. The issue represents a critical failure in authentication design where a feature intended to enhance security—TFA challenge verification—became a vector for complete authentication bypass.
The Vulnerability
The exploit requires only a single unauthenticated HTTP request to the Proxmox API ticket creation endpoint. No valid credentials, password knowledge, or TFA secrets are necessary. The complete request is:
POST /api2/json/access/ticket HTTP/1.1
Host: <pve-host>:8006
Content-Type: application/x-www-form-urlencoded
username=root@pam&password=x&tfa-challenge=1
When submitted to a vulnerable system, this request returns HTTP 200 OK with a complete authentication response including a valid root@pam ticket with full administrative privileges, a CSRF prevention token, and the complete capability map. The attacker-supplied password value (x in this example) is never validated. The tfa-challenge parameter value (1 in this example) is also never cryptographically verified. The response grants immediate access to all administrative API endpoints, including the terminal endpoint which provides a root shell on the virtualization host.
The researcher who discovered this vulnerability confirmed the bypass against a Proxmox VE 7 laboratory environment running on Debian 11 with pveproxy bound to localhost. The response includes a minted root@pam ticket with full privileges across all resource categories (nodes, VMs, storage, datacenters, SDN).

Root Cause Analysis
The bypass is enabled by three separate logic failures that combine to create an unauthenticated authentication path. Understanding each failure is critical for operators assessing their exposure and implementing mitigations.
Failure 1: TFA-Challenge Parameter Skips Password Verification
The ticket creation handler in PVE/API2/AccessControl.pm treats the presence of a tfa-challenge parameter as evidence that the user has already completed password authentication on a prior request. When this parameter is detected, the code skips the password verification step entirely and routes directly into two-factor authentication handling. The flaw is that password verification is only conditionally called—if TFA challenge is supplied, password validation is completely bypassed:
# PVE/API2/AccessControl.pm:149 (create_ticket_do)
if (!defined($tfa_challenge)) {
# We only verify this ticket if we're not responding to a TFA challenge, as in that case
# it is a TFA-data ticket and will be verified by `authenticate_user`.
($ticketuser, undef, $tfa_info) = PVE::AccessControl::verify_ticket($pw_or_ticket, 1);
}
...
} else {
($username, $tfa_info) = PVE::AccessControl::authenticate_user(
$username, $pw_or_ticket, $otp, $tfa_challenge,
);
}
When tfa_challenge is defined, the code calls authenticate_user instead of verify_ticket. The assumption is that authenticate_user will internally validate the password, but this assumption does not hold when TFA is in play.
Failure 2: TFA Lookup Returns Undefined for Default Users
Inside the authenticate_user function, when a tfa_challenge is detected, execution enters the “second factor” code path and never reaches the realm plugin’s password validation. Instead, the code immediately calls authenticate_2nd_new to verify the TFA challenge. Before that verification can happen, the system must look up the user’s TFA configuration to know what secrets or keys to use for challenge verification.
The vulnerability lies in the user_get_tfa function. For users without a keys field in the user.cfg file (which is the default for the built-in root@pam user and all LDAP/AD-synchronized users), the function would return early and not proceed to load the actual TFA configuration from the priv/tfa.cfg file:
# PVE/AccessControl.pm:2001 (user_get_tfa) - VULNERABLE VERSION
if (!$keys) {
return if !$realm_tfa; # <-- Returns undef for users without keys field
die "missing required 2nd keys\n";
}
Since the root@pam user has no keys field by default and typically no realm-mandated TFA is configured, this condition triggers and the function returns undef, never loading the actual TFA configuration file that would contain signed challenge tickets.
Failure 3: Challenge Verification Skipped When TFA Config is Undefined
The authenticate_2nd_new_do function checks whether a TFA configuration was loaded. If the configuration is undefined, it immediately returns without performing any cryptographic verification of the attacker-supplied challenge value:
# PVE/AccessControl.pm:756 (authenticate_2nd_new_do) - VULNERABLE VERSION
if (!defined($tfa_cfg)) {
return undef; # <-- Attacker's tfa-challenge is never verified
}
...
$tfa_challenge = verify_ticket($tfa_challenge, 0, $username); # <-- UNREACHABLE LINE
The actual cryptographic verification of the challenge ticket happens on line 803 using verify_ticket(), but that line is unreachable when $tfa_cfg is undefined. Any attacker-supplied value for tfa-challenge, including the single character “1”, passes this check.
With all three failures present, the request flow becomes: tfa-challenge supplied → skip password check → TFA config lookup returns undefined → skip challenge verification → mint full root ticket.
The Fix
The complete fix was released as a 13-line change across three sections of AccessControl.pm. The key change removes the early-return condition in user_get_tfa, forcing the function to always load the actual TFA configuration file:
@@ -753,6 +753,9 @@
my ($username, $realm, $tfa_response, $tfa_challenge) = @_;
my ($tfa_cfg, $realm_tfa) = user_get_tfa($username, $realm);
+ # FIXME: `$tfa_cfg` is now usually never undef - use cheap check for
+ # whether the user has *any* entries here instead whe it is available in
+ # pve-rs
if (!defined($tfa_cfg)) {
return undef;
}
@@ -805,6 +808,10 @@
$tfa_challenge = undef;
} else {
$tfa_challenge = $tfa_cfg->authentication_challenge($username);
+
+ die "missing required 2nd keys\n"
+ if $realm_tfa && !defined($tfa_challenge);
+
if (defined($tfa_response)) {
if (defined($tfa_challenge)) {
$tfa_done = 1;
@@ -1998,15 +2005,11 @@
$realm_tfa = PVE::Auth::Plugin::parse_tfa_config($realm_tfa)
if $realm_tfa;
- if (!$keys) {
- return if !$realm_tfa;
- die "missing required 2nd keys\n";
- }
-
my $tfa_cfg = cfs_read_file('priv/tfa.cfg');
if (defined($keys) && $keys !~ /^x(?:!.*)$/) {
add_old_keys_to_realm_tfa($username, $tfa_cfg, $realm_tfa, $keys);
}
+
return ($tfa_cfg, $realm_tfa);
}
The changelog entry from the release describes the fix in functional terms rather than security terms:
libpve-access-control (8.0.4) bookworm; urgency=medium
* Lookup of second factors is no longer tied to the 'keys' field in the
user.cfg. This fixes an issue where certain LDAP/AD sync job settings
could disable user-configured 2nd factors.
* Existing-but-disabled TFA factors can no longer circumvent realm-mandated
TFA.
-- Proxmox Support Team <support@proxmox.com> Thu, 20 Jul 2023 10:59:21 +0200
The release notes describe a configuration bug fix: two-factor authentication lookups are “no longer tied to the ‘keys’ field,” and disabled factors “can no longer circumvent realm-mandated TFA.” Both statements are technically accurate, but the notes do not communicate that the change closed a complete unauthenticated authentication bypass. This represents a significant disclosure gap—operators of affected systems were unaware they needed to patch until the issue became public in 2026.
Impact and Timeline
The Proxmox Security Team published official advisory PSA-2026-00043-1 on September 1, 2026, confirming that:
- The vulnerable code path was closed in July 2023 as an unintended side effect of a TFA configuration rework for an unrelated issue.
- At the time of the fix, the authentication bypass was unknown—the developers did not recognize it as a security issue requiring a CVE and advisory.
- The fix was therefore not backported to the Proxmox VE 7 branch, which remained end-of-life and exposed for three years.
- Exploitation in the wild has been reported within two days of public disclosure.
- A CVE number (CVE-2023-54391) was assigned after the advisory publication.
Affected Versions
The vulnerability affects libpve-access-control versions 7.0-7 through 8.0.3, corresponding roughly to:
- All Proxmox VE 7.x releases (7.0 through 7.4, now EOL since July 2024)
- Proxmox VE 8.0.0 through 8.0.3 (roughly the first month after 8.0 release)
Proxmox VE 6 is NOT affected (no tfa-challenge parameter exists), and Proxmox VE 8.0.4+ and 9.x are NOT affected. Users with any second factor already configured for their login are also not affected by this specific bypass, as they would still need to provide a valid challenge response.
Check your installed version with:
dpkg-query -W -f '${Version}\n' libpve-access-control
# or: pveversion -v
Detection Rules
Operators can detect probing and possible exploitation attempts using pveproxy access logs and syslog. The following Sigma detection rules provide hunting guidance for SIEM and log analysis systems.
Probe Detection
Repeated POST requests to the ticket endpoint from a single source IP are characteristic of probing. A burst of 308 or 401 responses indicates failed attempts against either vulnerable or patched systems:
title: Proxmox VE Access Ticket Endpoint Probe
id: 8f3c1a2e-5b7d-4c9e-9a1f-2d4e6f8a0b1c
status: experimental
author: neeythann
description: >
Detects repeated POST requests to /api2/json/access/ticket from a single
source IP. A burst of requests with 308/401 responses is characteristic
of probing for the tfa-challenge authentication bypass
(libpve-access-control <= 8.0.3).
logsource:
category: webserver
product: proxmox
detection:
selection:
cs-method: POST
cs-uri-stem|startswith: /api2/json/access/ticket
condition: selection | count(c-ip) > 5
timeframe: 5m
falsepositives:
- Misconfigured clients retrying failed logins
- Automated monitoring scripts
level: medium
Possible Exploitation
A successful (HTTP 200) response on the ticket endpoint from outside known administrative networks is the strongest single signal of exploitation:
title: Proxmox VE Successful Ticket Creation from Unexpected Source
id: 9d4e5f6a-7b8c-4d1e-9f2a-3c5e7f9a1b2d
status: experimental
author: neeythann
description: >
Detects a successful (HTTP 200) ticket creation on /api2/json/access/ticket
from a source IP that is not a known administrative host. On vulnerable
systems (libpve-access-control <= 8.0.3) the tfa-challenge bypass mints a
full root@pam ticket and returns 200 without a valid password.
logsource:
category: webserver
product: proxmox
detection:
selection:
cs-method: POST
cs-uri-stem|startswith: /api2/json/access/ticket
sc-status: 200
filter_known_admin:
c-ip:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
condition: selection and not filter_known_admin
falsepositives:
- Legitimate logins from non-whitelisted admin networks
- VPN or jump-host egress IPs
level: high
Post-Authentication Signal
A successful authentication for root@pam with no preceding failed attempt from the same source is a strong hunting signal on vulnerable systems:
title: Proxmox VE Successful root@pam Authentication via API
id: 1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d
status: experimental
author: neeythann
description: >
Detects a successful authentication for root@pam reported by pveproxy
syslog. On vulnerable systems the tfa-challenge bypass logs
"successful auth for user 'root@pam'" without any prior password
verification.
logsource:
category: application
product: proxmox
detection:
selection:
message|contains: "successful auth for user 'root@pam'"
condition: selection
falsepositives:
- Legitimate root@pam logins from the console or admin workstations
level: medium
Disclosure Timeline
The following table documents the complete disclosure timeline, from initial introduction of the vulnerable code to public advisory and CVE assignment:
| Date | Event |
|---|---|
| 2021-07 | tfa-challenge parameter introduced with Proxmox VE 7.0 |
| 2023-07-20 | Fix released in libpve-access-control 8.0.4 without CVE or security advisory |
| 2026-08-05 | Forum post describing unusual authentication behavior surfaces |
| 2026-08-29 | Investigation begins; patch diffing reveals authentication bypass |
| 2026-08-30 (3:48 PM EDT) | Vulnerability confirmed; vulnerability report submitted to Proxmox Security Team |
| 2026-08-30 (4:48 PM EDT) | Second report submitted with proof-of-concept exploit |
| 2026-08-31 (10:04 AM EDT) | Proxmox confirms PVE 7 affected; independent report received one day earlier |
| 2026-09-01 (2:32 AM EDT) | Official advisory PSA-2026-00043-1 published; exploitation reported in the wild |
| 2026-09-01 (8:00 PM EDT) | CVE-2023-54391 formally assigned |
Key Takeaways
- Feature-turned-vector: The TFA challenge parameter, designed to enhance security for two-factor authentication, became an attack vector for complete authentication bypass when the underlying validation logic was flawed.
- Silent fix, open gap: The 2023 fix closed the vulnerability but was released as a routine functional update without security signaling, leaving operators of EOL systems exposed for three years.
- Configuration assumptions: The vulnerability stems from unsafe assumptions about code paths—assuming that if TFA-challenge is supplied, password verification must have already occurred on a prior request.
- Multiple failure points required: Exploitation requires three separate logic failures to align: skipping password check, returning undefined TFA config, and short-circuiting challenge verification.
- Default installation exposure: No special configuration is required to be vulnerable—the default
root@pamuser with no TFA configured is exposed on all affected systems. - Unauthenticated access granted: The minted ticket grants full administrative API access, including root shell access through the terminal endpoint, with no constraints or time limitations.
Defensive Recommendations
- Immediate: Upgrade or patch. Upgrade affected systems to Proxmox VE 8.1 or 9.x, which are not vulnerable. For end-of-life PVE 7 systems that cannot upgrade immediately, apply the official stop-gap patch from PSA-2026-00043-1, which adds inline challenge verification to the vulnerable code path.
- Network isolation: Do not expose the pveproxy API/UI (port 8006) to untrusted networks. Bind pveproxy to localhost (
LISTEN_IP="127.0.0.1"in/etc/default/pveproxy, then restart pveproxy) and access it exclusively over SSH tunnels or corporate VPN. - Monitor login patterns: Implement the provided Sigma detection rules in your SIEM to alert on probing activity (repeated ticket requests), successful logins from unexpected sources, and successful
root@pamauthentications without preceding failed attempts. - Require MFA for all users: Enable two-factor authentication for the
root@pamaccount and all users with administrative privileges. Users with MFA already configured are not exposed by this specific bypass vector. - API firewall rules: Restrict access to the
/api2/json/access/ticketendpoint to known administrative IP ranges using firewall rules or WAF policies. Deny all other sources. - Audit account activity: Review pveproxy access logs and syslog for any successful
root@pamauthentications that do not match your known administrative access patterns. Treat any such match as potential compromise and investigate thoroughly. - Review API access logs: Examine historical API logs for activity following any suspicious ticket creation events. The minted tickets would allow an attacker to immediately perform privileged operations (VM creation, user modification, system reconfiguration).
Conclusion
The Proxmox VE 7.0–8.0.3 authentication bypass (CVE-2023-54391) represents a critical security failure that was inadvertently fixed but never publicly disclosed until exploitation appeared in the wild. The vulnerability demonstrates how complex authentication systems can fail when multiple layers of validation logic are built with unsafe assumptions about prior verification steps. The three-year disclosure gap between the fix and public awareness highlights the importance of security advisory processes and the risks posed by treating security-critical changes as routine functional updates. Operators of affected systems must prioritize immediate upgrades or patches and implement the recommended network isolation and monitoring measures to protect against exploitation. The incident serves as a reminder that end-of-life systems require ongoing security attention even after vendor support ends, as unfixed vulnerabilities may remain unknown to operators for extended periods.
Original text: “Proxmox VE 7.0–8.0.3: unauthenticated, single-request root auth bypass” by Nathan Golez, August 2026.


