It's a fire extinguisher mounted on the wall with the pin welded in — looks ready, does nothing
CVE-2026-115881 is a certificate-revocation-list enforcement failure in the EmbedThis GoAhead embedded web server (versions 3.4.5 through 6.1.0, OpenSSL backend only). The sslOpen() routine in src/openssl.c dutifully calls X509_STORE_load_locations() to ingest the configured CRL file, but never invokes X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK). Without that flag, OpenSSL's check_revocation() hits an early-return path and never consults the loaded CRL data. The practical result: a client certificate that an operator explicitly revoked — a stolen device, a terminated contractor's token, a decommissioned gateway — completes the mTLS handshake as if it were still valid and receives whatever access that identity grants. The bug was reported by Sébastien Féry of FoxIO in April 2026, patched in GoAhead 6.1.1 (released to OEMs August 2, public advisory October 12), and disclosed alongside two sister TLS flaws (CVE-2026-115884 LibreSSL chain-depth bypass, CVE-2026-115885 Mbed TLS DH truncation).
EmbedThis self-assessed this at CVSS 9.1 CRITICAL (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N). That vector overstates real-world severity in two important ways. First, AC:L is wrong: the bug fires only when the deployment uses the OpenSSL backend AND enables mutual TLS AND configures a CRL file AND enables issuer verification — four non-default, deliberately-configured conditions that must all be true simultaneously. CVSS 3.1 defines AC:H as 'specialized conditions beyond the attacker's control must exist,' which fits perfectly. Second, the attacker must already possess a revoked certificate signed by the target's trusted CA — not any certificate, but one that was once validly issued to them and later revoked. This implies prior authorized access and is far more restrictive than PR:N suggests. A corrected vector of AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N yields 7.4, which better matches reality. The vast majority of GoAhead's 'hundreds of millions' of deployed instances are consumer IoT devices (cameras, printers, routers) using basic auth or no auth at all — they never touch mTLS. The vulnerability's real teeth are in OT/ICS and defense deployments where mTLS with CRL enforcement is an explicit compliance requirement.
4 steps from start to impact.
Identify GoAhead mTLS endpoint
Server: GoAhead HTTP header (Shodan shows ~580K internet-facing instances) and by observing that the TLS handshake sends a CertificateRequest message. The attacker must determine that this specific deployment uses the OpenSSL backend, not Mbed TLS — firmware analysis, vendor documentation, or behavioral fingerprinting (cipher-suite ordering differences) can reveal this.- Target device runs GoAhead 3.4.5–6.1.0
- OpenSSL backend compiled in (not Mbed TLS)
- mTLS enabled with CRL configured
- Device management interface network-reachable to attacker
- mTLS is a non-default, deliberately-configured feature — most GoAhead instances use basic auth or session cookies
- Many GoAhead devices sit behind NAT or on isolated management VLANs, not directly internet-facing
- The OpenSSL vs. Mbed TLS backend choice is vendor-specific and not always obvious externally
Server: GoAhead identifies instances; openssl s_client -connect host:port reveals whether a CertificateRequest is sent during handshakeObtain a revoked client certificate
- Attacker possesses private key material for a certificate issued by the target's CA
- That certificate's serial number appears in the target's CRL
- Certificate is otherwise valid (not expired, correct extended key usage)
- Requires prior authorized access to the target's PKI trust domain — this is inherently an insider or post-compromise scenario
- Many organizations use short-lived certificates (hours/days) that expire before revocation matters
- Hardware security modules or TPM-bound keys prevent certificate extraction even from compromised devices
Present revoked certificate in mTLS handshake
CertificateVerify phase of the mutual TLS handshake. Because GoAhead loaded the CRL but never set X509_V_FLAG_CRL_CHECK, OpenSSL's verification callback skips revocation checking entirely. The handshake completes successfully. No exploit toolkit is needed — standard curl --cert client.pem --key client.key https://target/ suffices.- Network path to the mTLS endpoint
- Revoked certificate + private key in hand
- Network segmentation may block access to the management interface from attacker-controlled hosts
- TLS inspection at network boundaries may log or block the connection
- Device-level IP allowlists or firewall rules may restrict which source IPs can reach the mTLS port
Access protected resource as revoked identity
- Successful mTLS handshake (step 3 succeeded)
- Revoked identity still mapped to an authorization role on the device
- Some deployments implement application-layer authorization checks beyond mTLS (role removed when cert revoked)
- Audit logging of management actions may trigger alerts even if the handshake succeeds
- Physical interlocks on OT devices may limit remote damage
X509_STORE_set_flags patch). Since GoAhead is distributed as source to OEMs, defenders must contact their device vendors (Siemens, Honeywell, Palo Alto, etc.) for updated firmware. Track vendor response and schedule firmware deployment within the 180-day noisgate remediation SLA for HIGH severity. Prioritize OT/ICS devices.- Updating the CRL file more frequently — the CRL is already loaded into memory; the bug is that OpenSSL never reads it. A fresher CRL still goes unread. This control addresses a problem that does not exist here.
- WAF or IPS rules — the vulnerability is in the TLS handshake layer, before any HTTP traffic is generated. WAF/IPS cannot inspect or block the client-certificate exchange.
- Switching to OCSP stapling alone — OCSP stapling is a server-certificate verification mechanism (server proves its own cert is valid to the client). It does not affect client-certificate revocation checking, which is what this CVE bypasses.
- Disabling the CRL configuration — removing the CRL from GoAhead's config eliminates the false sense of security but does not add any protection. Without the CRL, revoked certs were already accepted; with it, they were also accepted. The fix is to enforce, not remove.
The supporting signals.
| In-the-Wild Exploitation | No evidence of active exploitation. Not listed in CISA KEV. No vendor or researcher reports of in-the-wild use as of 2026-10-28. The niche prerequisites (mTLS + CRL + revoked cert possession) make mass exploitation unlikely. |
|---|---|
| Proof-of-Concept | No standalone PoC repository. The FoxIO blog post provides a detailed technical walkthrough and confirmed exploitation with curl --cert against GoAhead 6.1.0 / OpenSSL 3.6.2. No dedicated GitHub repo, ExploitDB entry, Nuclei template, or Metasploit module found on pocindex.io or GitHub as of 2026-10-28. Reproduction requires only standard TLS tooling — no weaponized exploit needed. |
| EPSS Score | Not yet scored. CVE-2026-115881 is not yet in the NVD or MITRE CVE databases (EmbedThis states the ID has been requested). EPSS cannot score an ID that lacks an NVD record. Expect a low EPSS percentile given the narrow prerequisite chain. |
| CISA KEV Status | Not listed. No active exploitation evidence, no KEV entry. |
| CVSS Vector (Vendor) | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N → 9.1 Critical per GHSA-5m75-xq69-c3c5. AC:L is overstated; realistic vector is AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N → 7.4 High. |
| Affected Versions | GoAhead 3.4.5 through 6.1.0 when compiled with the OpenSSL-compatible backend (ME_COM_OPENSSL=1). Mbed TLS backend builds are not affected — that backend has its own CRL checking code path. Versions prior to 3.4.5 did not have CRL loading support. |
| Fixed Version | GoAhead 6.1.1 (released to OEMs 2026-08-02, public advisory 2026-10-12). The patch is a single-line addition: X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK) after CRL loading in src/openssl.c. No distro backports — GoAhead is distributed as source to device OEMs who build it into firmware. |
| Internet Exposure | Shodan indexes ~580,000 GoAhead instances with Server: GoAhead headers. However, the fraction using mTLS with CRL is a small subset — most are consumer IoT (IP cameras, printers) with basic or no authentication. The exploitable population is concentrated in OT/ICS and defense deployments. |
| Disclosure Timeline | 2026-04-30: Reported to EmbedThis by Sébastien Féry (FoxIO) → 2026-08-02: GoAhead 6.1.1 released to OEMs → 2026-10-12: Public advisories and GHSA published → 2026-10-26: FoxIO blog post with technical details |
| Reporter | Sébastien Féry of FoxIO. Part of a coordinated disclosure of three GoAhead TLS flaws (SA-0004, SA-0005, SA-0006). |
Sources.
- FoxIO Technical Blog — Three TLS Bugs in GoAhead
- GitHub Security Advisory GHSA-5m75-xq69-c3c5
- GoAhead 6.1.1 Release Notes
- CyberSecurityNews — GoAhead TLS Vulnerabilities
- The Hacker News — GoAhead TLS Flaws
- Industrial Cyber — GoAhead Flaws in ICS Devices
- Nozomi Networks — GoAhead Security Flaws
- Shodan — GoAhead Server Search
Why this verdict
- AC:L → AC:H correction: The vendor vector uses Attack Complexity: Low, but four non-default conditions must all be true simultaneously (OpenSSL backend, mTLS enabled, CRL configured, issuer verification on). CVSS 3.1 defines AC:H as 'specialized conditions beyond the attacker's control' — this is textbook AC:H, dropping the base from 9.1 to 7.4.
- Revoked-certificate requirement is a severe population narrower: The attacker must possess the private key of a certificate that was (a) issued by the target's specific CA and (b) subsequently revoked. This inherently means prior authorized access — an insider threat, a stolen device, or a post-compromise scenario. This is not a drive-by exploit; it's a targeted attack with per-deployment prerequisites.
- mTLS + CRL is a minority deployment pattern: The vast majority of GoAhead's hundreds of millions of deployed instances are consumer IoT devices using basic HTTP auth or session cookies. mTLS with CRL is principally configured in OT/ICS environments following IEC 62443 or defense environments following STIGs. Conservatively, <5% of the installed base runs the vulnerable configuration.
- Role multiplier — OT/ICS controllers (Siemens, Honeywell, Rockwell): GoAhead is embedded in PLCs, HMIs, and industrial gateways from these vendors, where mTLS + CRL is a realistic configuration for IEC 62443 compliance. If the chain succeeds on an ICS controller, the attacker regains management-plane access to a safety-critical device — read/write process variables, modify setpoints, upload logic. This is an OT-safety impact outcome. These OT deployments represent >1% of GoAhead's installed base given the vendor list, so the verdict floor is HIGH per the deployment-role blast radius rule.
- Role multiplier — network edge appliances (Palo Alto): Palo Alto Networks embeds GoAhead in some product management interfaces. If mTLS + CRL is used for management access and the chain succeeds, a revoked admin cert gets firewall management access → configuration exfiltration, rule manipulation, credential harvesting. Blast radius is per-appliance but each appliance controls a network perimeter. Outcome reinforces the HIGH floor.
- Role multiplier — consumer IoT (majority of installs): On cameras, printers, and consumer routers, mTLS is essentially never configured. The chain does not succeed in this role. These devices do not raise the floor.
- No active exploitation or public PoC tooling: No KEV listing, no EPSS score, no weaponized exploit code. The FoxIO blog provides a technical walkthrough but the attack requires per-target certificate material, limiting scalability.
Why not higher?
CRITICAL would require either (a) ≥10% of GoAhead installs canonically occupying a high-value role with this specific configuration, or (b) the attack chain producing fleet-scale impact. Neither condition holds. GoAhead is primarily a consumer IoT web server — the OT/ICS and network-edge fraction is significant but well under 10% of the total installed base. Additionally, exploitation requires per-target revoked certificate material, making mass exploitation impractical. The impact is per-device, not fleet-scale, and there is no lateral movement or privilege escalation beyond the revoked identity's existing role.
Why not lower?
MEDIUM would require breaking the HIGH floor, which demands evidence that the OT/ICS deployment role is <1% of the installed base. Given that Siemens, Honeywell, Rockwell, GE, and Digi all embed GoAhead in industrial products, and these collectively represent millions of deployed devices against GoAhead's 'hundreds of millions' total, the OT fraction comfortably exceeds 1%. The OT-safety impact outcome is real and documented — these are process-control devices where management-plane access can affect physical processes. The CRL bypass also undermines a specific compliance control (IEC 62443-3-3 SR 1.3, certificate revocation), meaning the organizational impact extends beyond the technical exploit to audit and compliance posture.
Crowdsourced verification payload.
Run from an auditor workstation with network access to the target GoAhead endpoint. Requires curl and openssl CLI. No authentication or credentials needed. Invoke as: bash check_cve_2026_115881.sh <host> [port] (port defaults to 443).
#!/usr/bin/env bash
# CVE-2026-115881 — GoAhead OpenSSL CRL Enforcement Bypass Checker
# Checks version range and mTLS presence to flag vulnerable deployments.
# Exit codes: 1=VULNERABLE 0=PATCHED 2=UNKNOWN
set -uo pipefail
HOST="${1:?Usage: $0 <host> [port]}"
PORT="${2:-443}"
echo "=== CVE-2026-115881 — GoAhead CRL bypass checker ==="
echo "Target: ${HOST}:${PORT}"
RESULT="UNKNOWN"
MTLS="unknown"
# Step 1: Banner grab
HEADERS=$(curl -sSk -I --connect-timeout 5 "https://${HOST}:${PORT}/" 2>/dev/null || true)
SVR=$(echo "$HEADERS" | grep -i '^Server:' | head -1 | tr -d '\r')
if [ -n "$SVR" ]; then
echo "[*] Server header: $SVR"
else
echo "[?] No Server header — may still be GoAhead."
fi
# Step 2: Version check
VER=$(echo "$SVR" | grep -oiP '(?<=GoAhead[ /-])\d+\.\d+(\.\d+)?' || true)
if [ -n "$VER" ]; then
echo "[*] GoAhead version: $VER"
IFS='.' read -r MAJ MIN PAT <<< "$VER"
PAT=${PAT:-0}
if (( MAJ > 6 || (MAJ == 6 && MIN > 1) || (MAJ == 6 && MIN == 1 && PAT >= 1) )); then
echo "[+] Version $VER >= 6.1.1 — patched."
RESULT="PATCHED"
elif (( MAJ < 3 || (MAJ == 3 && MIN < 4) || (MAJ == 3 && MIN == 4 && PAT < 5) )); then
echo "[+] Version $VER < 3.4.5 — not in affected range."
RESULT="PATCHED"
else
echo "[!] Version $VER in vulnerable range (3.4.5 – 6.1.0)."
RESULT="VULNERABLE"
fi
else
echo "[?] Version not detected from banner."
fi
# Step 3: mTLS probe
echo "[*] Probing TLS handshake for client-cert request..."
TLS_OUT=$(echo Q | openssl s_client -connect "${HOST}:${PORT}" 2>&1 || true)
if echo "$TLS_OUT" | grep -q "Acceptable client certificate CA names"; then
echo "[!] mTLS detected — server requests client certificates."
MTLS="yes"
elif echo "$TLS_OUT" | grep -q "No client certificate CA names sent"; then
echo "[+] No client-cert request — mTLS not active."
MTLS="no"
else
echo "[?] mTLS status indeterminate."
fi
# Verdict
echo ""
if [ "$RESULT" = "PATCHED" ]; then
echo "PATCHED"
exit 0
elif [ "$RESULT" = "VULNERABLE" ]; then
if [ "$MTLS" = "no" ]; then
echo "[*] Vulnerable version but mTLS not active — low risk."
echo "PATCHED"
exit 0
fi
echo "[!] GoAhead $VER with mTLS active — VULNERABLE to CVE-2026-115881."
echo "[!] Confirm OpenSSL backend and CRL config on device."
echo "VULNERABLE"
exit 1
else
if [ "$MTLS" = "yes" ]; then
echo "[!] mTLS active, version unknown — treat as VULNERABLE."
echo "VULNERABLE"
exit 1
fi
echo "[?] Insufficient data to determine status."
echo "UNKNOWN"
exit 2
fi