Skip to content
GOAHEAD-SA-2026-0004 / CVE-2026-115884

GOAHEAD-SA-2026-0004 / CVE-2026-115884

github.com • October 27, 2026

Important — OpenSSL builds are NOT vulnerable. This bypass is triggered only when GoAhead is linked against the LibreSSL legacy X.509 verifier (LibreSSL 3.2.x or 3.3.2-3.3.6). Builds linked against OpenSSL (any supported version) — the preferred and default TLS backend for GoAhead — are not exposed. Builds linked against BoringSSL, AWS-LC, or LibreSSL 4.x are likewise not exposed. The mbedtls backend uses a separate verification path and is also not exposed.

Important — OpenSSL builds are NOT vulnerable. This bypass is triggered only when GoAhead is linked against the LibreSSL legacy X.509 verifier (LibreSSL 3.2.x or 3.3.2-3.3.6). Builds linked against OpenSSL (any supported version) — the preferred and default TLS backend for GoAhead — are not exposed. Builds linked against BoringSSL, AWS-LC, or LibreSSL 4.x are likewise not exposed. The mbedtls backend uses a separate verification path and is also not exposed.

GoAhead's mutual TLS (mTLS) client-certificate verification accepts an attacker-controlled over-depth certificate chain when the deployment is configured to require client certificates without checking issuer trust ( ME_GOAHEAD_SSL_VERIFY_PEER=1 , ME_GOAHEAD_SSL_VERIFY_ISSUER=0 ) and is linked against LibreSSL releases where the legacy X.509 verifier is active by default (3.2.x, 3.3.2-3.3.6).

An attacker who can reach an mTLS-protected HTTPS endpoint, on an affected LibreSSL-linked build, can present a self-signed certificate chain longer than the server's configured VERIFY_DEPTH (10) and complete the TLS handshake as an authenticated client, without possessing any trusted key material.

The practical bypass is triggered by a known defect in LibreSSL's legacy verifier; the same chain against an OpenSSL-linked build is rejected because OpenSSL surfaces X509_V_ERR_CERT_CHAIN_TOO_LONG (error 22), which the callback's default: branch refuses. The underlying fragility in GoAhead's verification callback is nevertheless backend-agnostic and is fixed independent of the LibreSSL trigger as defence in depth.

Scope — exploitation requires all of the following:

The deployment enables mutual TLS with ME_GOAHEAD_SSL_VERIFY_PEER=1 .

The deployment disables issuer trust checking with ME_GOAHEAD_SSL_VERIFY_ISSUER=0 . Deployments that set ME_GOAHEAD_SSL_VERIFY_ISSUER=1 are not affected .

GoAhead is linked against LibreSSL 3.2.x or 3.3.2-3.3.6. Builds linked against OpenSSL (the preferred TLS backend), BoringSSL, AWS-LC, or LibreSSL 4.x are not affected — these backends surface over-depth chains as X509_V_ERR_CERT_CHAIN_TOO_LONG (error 22), which the callback's default: branch rejects.

The attacker can reach the mTLS-gated HTTPS endpoint and present a certificate chain of more than 10 certificates. No trusted key material, no prior authentication, and no knowledge of any legitimate client identity is required.

Mutual TLS is an opt-in feature. Default GoAhead builds do not perform any client-certificate verification and are not exposed to this defect.

The GoAhead verification callback enforces the chain-depth limit only when no other error has been reported:

If the underlying verifier has already set any non-zero error, this guard does nothing and the callback falls through to an error-code switch. Under ME_GOAHEAD_SSL_VERIFY_ISSUER=0 , the switch accepts X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY (error 20).

Against LibreSSL 3.2.x / 3.3.2-3.3.6, an attacker-controlled chain of more than VERIFY_DEPTH=10 certificates causes the legacy verifier to surface error 20 at the callback. The depth guard is skipped, the switch accepts the chain, and the TLS handshake completes. Any HTTP request on that connection is subsequently treated as having presented a valid client certificate.

Against OpenSSL (all current versions), BoringSSL, AWS-LC, and LibreSSL 4.x, the same chain causes the verifier to surface X509_V_ERR_CERT_CHAIN_TOO_LONG (error 22) instead. The callback's default: branch rejects error 22, so the handshake fails and no bypass occurs on these backends. The defect in GoAhead's callback is nevertheless a defence-in-depth concern on all backends, because it relies on the underlying verifier to always map over-depth to error 22.

The verification callback is modified to enforce the chain-depth limit unconditionally, before any error-code-specific acceptance path runs. The fix consults the callback's reported depth directly ( X509_STORE_CTX_get_error_depth ) rather than inferring from the error code. This is backend-agnostic: no version check or feature detection is required, and the fix is effective on OpenSSL, BoringSSL, AWS-LC, and all LibreSSL versions.

Applied to src/openssl.c in verifyClientCertificate() :

Reported by Sébastien Féry.

Extracted Entities