core-jmp core-jmpdeath of core jump

Proxmox VE 7.0–8.0.3: Unauthenticated Single-Request Root Auth Bypass (CVE-2023-54391)

An unauthenticated authentication bypass in Proxmox VE 7.0–8.0.3 allows attackers to mint a full root@pam ticket with a single HTTP request. The vulnerability was fixed in libpve-access-control 8.0.4 without a CVE or security advisory, leaving EOL systems exposed for three years.

oxfemale September 2, 2026 13 min read 122 reads
Export PDF
Proxmox VE 7.0–8.0.3: Unauthenticated Single-Request Root Auth Bypass (CVE-2023-54391)
Original text: “Proxmox VE 7.0–8.0.3: unauthenticated, single-request root auth bypass”Nathan Golez, August 30, 2026. Code blocks, tables, and technical analysis are reproduced verbatim with attribution captions.

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:

DateEvent
2021-07tfa-challenge parameter introduced with Proxmox VE 7.0
2023-07-20Fix released in libpve-access-control 8.0.4 without CVE or security advisory
2026-08-05Forum post describing unusual authentication behavior surfaces
2026-08-29Investigation 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
Source: original article.

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@pam user 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@pam authentications without preceding failed attempts.
  • Require MFA for all users: Enable two-factor authentication for the root@pam account 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/ticket endpoint 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@pam authentications 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.

oxfemale Vulnerability research, reverse engineering, and exploit development.
// Discussion