A significant authentication correlation vulnerability has been disclosed and resolved in OpenBSD ldapd, the lightweight Lightweight Directory Access Protocol daemon integrated into the OpenBSD operating system. Designated as CVE-2026-103547 and cataloged in GitHub Advisory GHSA-f239-ggxr-g679, the flaw enables unauthenticated remote network actors to hijack authenticated directory sessions or complete unauthorized LDAP Binds as another identity due to improper tracking of asynchronous BSD authentication helper tokens.

Delegated Authentication in OpenBSD Security Architecture

The OpenBSD operating system is internationally recognized for its uncompromising security auditing and privilege separation paradigms. Within ldapd, authentication requests can be delegated to the operating system's BSD Authentication framework (bsd_auth). When an enterprise client issues an LDAP Simple Bind request with credentials, ldapd dispatches the request to an unprivileged worker process that validates passwords against the system authentication database.

Because directory requests are processed asynchronously via event loops (libevent), the daemon must correlate incoming authentication responses from the backend worker with the originating client connection.

The Root Cause: File Descriptor Reuse and Message ID Collision (CWE-287)

Prior to errata 057 (OpenBSD 7.8) and errata 021 (OpenBSD 7.9), ldapd correlated delegated authentication results using only two parameters:

  • The client's socket file descriptor integer (fd).
  • The client-supplied LDAP message ID (msgid).
// Vulnerable Authentication Tracking Pattern (ldapd)
struct auth_req {
    int client_fd;       // Operating system file descriptor
    int msgid;           // Attacker-controlled LDAP message identifier
    char *user_dn;       // Identity to bind
};

// When BSD auth helper finishes verification:
void auth_complete(int client_fd, int msgid, int success) {
    struct conn *conn = find_conn_by_fd(client_fd);
    if (conn && conn->current_msgid == msgid) {
        if (success) {
            conn->state = LDAP_STATE_BOUND; // Grants access!
        }
    }
}

Because operating systems aggressively recycle the lowest available file descriptor integer upon socket closure, a race condition emerges when network latency occurs or clients disconnect:

  1. A legitimate privileged user initiates an LDAP bind for uid=admin,dc=example,dc=com over connection A (assigned fd = 6, msgid = 1).
  2. Before the authentication worker completes verification, connection A encounters a network hiccup or closes.
  3. An attacker immediately opens a new TCP connection to ldapd. The operating system kernel assigns the newly freed socket the identical descriptor integer: fd = 6.
  4. The attacker transmits an LDAP Bind request with msgid = 1.
  5. The delayed authentication worker returns a positive success status for fd = 6, msgid = 1.
  6. ldapd erroneously matches the success response to the attacker's connection, marking the attacker as fully authenticated and bound under the administrator's distinguished name (DN).

Vulnerability & Remediation Matrix

Component Vulnerable Pattern OpenBSD Errata Fix (Commit 4f3f58e)
Correlation Key Transient (client_fd, msgid) pair Monotonically increasing 64-bit unique request_id
Socket Teardown Orphaned worker responses persist in queue Socket closure explicitly purges pending delegated auth callbacks
Null Dereference Missing connection lookup triggers daemon segfault Defensive pointer validation returns error rather than crashing

Remediation & Defense Actions

  1. Apply OpenBSD Errata Patches: Apply official errata patches immediately via syspatch on supported architectures:
    # On OpenBSD 7.9:
    syspatch
    # Or apply source patch 021_ldapd.patch.sig
  2. Verify ldapd Status: Check whether ldapd is active on the system; note that ldapd is disabled by default in standard OpenBSD base installations:
    rcctl check ldapd
  3. Enforce Mutual TLS (LDAPS): Restrict directory communication to encrypted channels with client certificate validation, preventing arbitrary unauthenticated TCP connection churning on port 389.