27-Year Authentication Bypass and Kernel Heap Over-read Fixed in OpenBSD’s PPP Stack
A critical architectural flaw has been identified within the OpenBSD Point-to-Point Protocol (PPP) stack, specifically targeting the Password Authentication Protocol (PAP) validation logic. This vulnerability allows an unauthenticated attacker to bypass security checks entirely, granting unauthorized access to network resources by manipulating authentication frames.
While a patch was deployed in June 2026, the root cause traces back to legacy code merged in July 1999. This makes it one of the most significant long-standing authentication vulnerabilities in the history of modern operating systems, highlighting the hidden risks that “stable” legacy code can harbor over decades.
Technical Analysis: The Logic Flaw in sppp_pap_input()
The vulnerability is located within the sppp(4) subsystem, specifically inside the sppp_pap_input() function, which manages synchronous PPP and PPPoE (PPP over Ethernet) connections. The failure lies in how the system handles credential verification using the bcmp() function.
During the PAP handshake, the system attempts to compare user-provided credentials against stored secrets. The original implementation relied on length fields provided directly by the incoming network packet without verifying if those lengths were non-zero or logically consistent with the stored credentials. The vulnerable code block was structured as follows:
if (name_len > AUTHMAXLEN ||
passwd_len > AUTHMAXLEN ||
bcmp(name, sp->hisauth.name, name_len) != 0 ||
bcmp(passwd, sp->hisauth.secret, passwd_len) != 0) {
/* authentication failed */
}
In C, the bcmp() function compares two memory areas up to a specified number of bytes. If an attacker sends a PAP frame where both name_len and passwd_len are set to zero, bcmp() immediately returns 0, signaling that the “empty” inputs are equal to the stored credentials. Because there was no minimum length requirement, the system would treat a zero-byte authentication attempt as a successful match, effectively bypassing the entire security mechanism.
Secondary Impact: Kernel Heap Over-read
Beyond the authentication bypass, the flaw introduced a significant memory safety risk. Because credential buffers were dynamically allocated using malloc(strlen(…) + 1), the system was susceptible to a heap over-read. If an attacker provided a length value larger than the actual data sent in the packet, bcmp() would continue reading past the allocated buffer in kernel space. This could allow a sophisticated attacker to leak sensitive information from the kernel heap.
Exploitation Vector and Attack Scenario
This vulnerability is remotely exploitable via the PPPoE data path, following the execution flow: pppoe_data_input → pppoeintr → sppp_input → sppp_pap_input. An attacker does not require valid credentials or existing network access to trigger the flaw.
In a real-world scenario, a malicious actor operating on the same broadcast domain as the target can deploy a rogue PPPoE server. By impersonating a legitimate Access Concentrator (AC), the attacker can complete the PPP handshake via the zero-length bypass and move directly into IPCP (IP Control Protocol) negotiation. Once IP connectivity is established, the attacker can perform man-in-the-middle (MITM) attacks, intercepting or redirecting all subsequent network traffic.
A proof-of-concept demonstration reported by Argus Blog successfully exploited this on OpenBSD 7.6, proving that a rogue server could receive a PAP_ACK and establish a full session using nothing but empty credentials.
Historical Context and The Fix
The disparity in security posture within the stack is striking. While OpenBSD’s CHAP (Challenge Handshake Authentication Protocol) implementation correctly validated credential lengths, the PAP handler lacked these checks for over 27 years. The risk was further compounded in 2009 when dynamic memory allocation was introduced, turning a logic error into a potential memory leak.
The updated, hardened implementation resolves this by enforcing strict length equality. The system now ensures that the length of the incoming credentials matches the exact length of the stored credentials before any comparison occurs:
if (name_len != strlen(sp->hisauth.name) ||
passwd_len != strlen(sp->hisauth.secret) ||
bcmp(name, sp->hisauth.name, name_len) != 0 ||
bcmp(passwd, sp->hisauth.secret, passwd_len) != 0) {
/* authentication failed */
}
This patch effectively mitigates both the authentication bypass and the kernel heap over-read. We strongly recommend that administrators using OpenBSD in PPPoE-enabled environments apply the latest security updates immediately and implement network segmentation to limit exposure to untrusted broadcast domains.