← Back to Feed CACHED · 2026-10-27 20:05:22 · CACHE_KEY CVE-2026-115881
CVE-2026-115881 · CWE-299 · Disclosed 2026-10-12

EmbedThis GoAhead OpenSSL backend CRL enforcement bypass accepting revoked mTLS client certificates

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

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.

"GoAhead loads the revocation list then never reads it — but only mTLS+CRL deploys are exposed"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify GoAhead mTLS endpoint

The attacker locates a GoAhead-powered device management interface that requires client-certificate authentication. This can be fingerprinted via the 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.
Conditions required:
  • 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
Where this breaks in practice:
  • 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
Detection/coverage: Shodan/Censys dork Server: GoAhead identifies instances; openssl s_client -connect host:port reveals whether a CertificateRequest is sent during handshake
STEP 02

Obtain a revoked client certificate

The attacker must possess a client certificate and private key that (a) was validly issued by the target deployment's trusted CA and (b) has been added to the configured CRL. Realistic scenarios include a terminated employee retaining their device certificate, a physically stolen IoT/OT device whose cert was revoked, or a compromised endpoint whose certificate the SOC revoked as part of incident response. The key point is that the attacker previously had legitimate access.
Conditions required:
  • 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)
Where this breaks in practice:
  • 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
Detection/coverage: PKI audit logs show certificate issuance; SIEM correlation of revoked-cert serial numbers against TLS connection logs can flag reuse attempts
STEP 03

Present revoked certificate in mTLS handshake

The attacker initiates a TLS connection to the GoAhead endpoint and presents the revoked client certificate during the 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.
Conditions required:
  • Network path to the mTLS endpoint
  • Revoked certificate + private key in hand
Where this breaks in practice:
  • 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
Detection/coverage: No CVE-specific scanner exists yet; version-based detection (GoAhead <6.1.1 + mTLS probe) is the current approach; the FoxIO blog provides the technical basis for a Nuclei template
STEP 04

Access protected resource as revoked identity

With the handshake accepted, the attacker operates with the full privileges of the revoked certificate's identity — typically device management, configuration read/write, firmware upload, or API access depending on the deployment. On an OT/ICS controller (Siemens, Honeywell, Rockwell devices use GoAhead), this could mean reading process variables, modifying setpoints, or uploading malicious logic. On a network appliance, it could mean reconfiguring firewall rules or exfiltrating configuration data including credentials.
Conditions required:
  • Successful mTLS handshake (step 3 succeeded)
  • Revoked identity still mapped to an authorization role on the device
Where this breaks in practice:
  • 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
Detection/coverage: Application-layer access logs showing activity from a certificate serial number that should be revoked; SIEM rule correlating CRL entries against active session logs
03 · Compensating Control

1
HIGH 6.8→MEDIUM 5.3
SEVERITY REDUCED
Segment mTLS management interfaces onto a dedicated, restricted management VLAN — Move all GoAhead device management endpoints behind a jump host or PAM gateway on a management VLAN with strict source-IP allowlists. This breaks attack-path step 1 (network reachability) and step 3 (handshake delivery) by ensuring only authorized management stations can reach the mTLS port. Deploy within 30 days per the noisgate mitigation SLA for HIGH severity.
2
HIGH 6.8→LOW 3.1
SEVERITY REDUCED
Implement application-layer authorization checks independent of certificate validity — Configure the device or a reverse proxy to cross-reference the connecting certificate's serial number against an allowlist or OCSP responder at the application layer, separate from the TLS handshake. This catches revoked certificates even when the TLS stack fails to. Some GoAhead deployments support custom authentication callbacks. Deploy within 30 days per the noisgate mitigation SLA.
3
HIGH 6.8→HIGH 6.0
Monitor for revoked-certificate serial numbers in TLS session logs — Extract client-certificate serial numbers from TLS connection logs (or deploy a TLS-inspecting proxy that logs them) and create a SIEM rule that alerts when a serial number matching any CRL entry establishes a session. This is detective, not preventive, but provides visibility into exploitation attempts. Deploy within 30 days.
4
HIGH 6.8→IGNORE 0.0
SEVERITY REDUCED
Request firmware updates from device OEMs incorporating GoAhead 6.1.1 — The definitive fix is GoAhead 6.1.1 (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.
5
HIGH 6.8→LOW 2.5
SEVERITY REDUCED
Rotate to short-lived certificates (≤24h) where supported — If the deployment's PKI supports automated certificate issuance (ACME, EST, CMPv2), switch to short-lived client certificates. A revoked certificate that expires in hours is useless to an attacker regardless of whether the CRL is checked. This neutralizes the vulnerability by making the certificate's natural expiry faster than any revocation workflow. Deploy within 30 days.
What doesn't work
  • 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.
04 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNo 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-ConceptNo 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 ScoreNot 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 StatusNot 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 VersionsGoAhead 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 VersionGoAhead 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 ExposureShodan 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 Timeline2026-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
ReporterSébastien Féry of FoxIO. Part of a coordinated disclosure of three GoAhead TLS flaws (SA-0004, SA-0005, SA-0006).

Sources.

  1. FoxIO Technical Blog — Three TLS Bugs in GoAhead
  2. GitHub Security Advisory GHSA-5m75-xq69-c3c5
  3. GoAhead 6.1.1 Release Notes
  4. CyberSecurityNews — GoAhead TLS Vulnerabilities
  5. The Hacker News — GoAhead TLS Flaws
  6. Industrial Cyber — GoAhead Flaws in ICS Devices
  7. Nozomi Networks — GoAhead Security Flaws
  8. Shodan — GoAhead Server Search
05 · The Call

Final Verdict
↓ DOWNGRADED to HIGH (6.8/10)

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.

06 · Verification

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).

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/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