Three TLS Bugs in GoAhead

Hacker News Top News

Summary

FoxIO披露了GoAhead嵌入式Web服务器中三个独立的TLS漏洞:OpenSSL后端未强制执行CRL吊销检查(CVSS 9.1)、LibreSSL旧版验证器可绕过证书链深度限制(CVSS 7.4),以及Mbed TLS后端的DH参数缓冲区错误导致TLS 1.2会话可被解密(CVSS 5.9),影响数亿台IoT、防火墙和工业控制设备,建议升级至6.1.1或更高版本。

No content available
Original Article
View Cached Full Text

Cached at: 10/28/26, 01:51 AM

# Choose Your Backend: Three TLS Bugs in GoAhead - FoxIO | Cyber Innovation Source: [https://foxio.io/blog/choose-your-backend-three-tls-bugs-in-goahead](https://foxio.io/blog/choose-your-backend-three-tls-bugs-in-goahead) ## TLDR GoAhead is used in hundreds of millions of IoT, Firewall, OT, and Military devices including those from Palo Alto Networks, Comcast, D\-Link, HP, Canon, Honeywell, GE, Oracle, Siemens, Rockwell, Digi, Lockheed Martin, Boeing, and more\. Three independent bugs in GoAhead's TLS integrations can leave revoked client certificates accepted, encrypted sessions recoverable to an observer or a configured chain\-depth limit unenforced\. Exposure depends on the TLS library and the verification settings built into the device: - OpenSSL\-compatible backend \- Critical, CVSS 9\.1 \- CRL loaded but not enforced, revoked client certificates are silently accepted\. GOAHEAD\-SA\-2026\-0006\. - LibreSSL legacy verifier \- High, CVSS 7\.4 \- An over\-depth client chain is accepted when client certificates are required but issuer checking is disabled\. This bypasses the chain\-depth restriction\. GOAHEAD\-SA\-2026\-0004\. - Mbed TLS \- Medium, CVSS 5\.9 \- A buffer\-length typo reduces a 2048\-bit DH modulus to one byte\. TLS 1\.2 DHE\_RSA sessions are decryptable when the client accepts the broken parameters\. GOAHEAD\-SA\-2026\-0005\. TLS build GoAhead versions Required configuration Fix or mitigation **OpenSSL\-compatible backend** \>= 3\.4\.5, <= 6\.1\.0 mTLS enabled with a CRL configured\. Revoked client certificates remain accepted even with issuer verification enabled\. Upgrade to**6\.1\.1 or later**\. **Mbed TLS backend** \>= 4\.0\.2, <= 6\.1\.0 TLS 1\.2 DHE\_RSA negotiated with a client that accepts the broken DH parameters\. Upgrade to**6\.1\.1 or later**, disable finite\-field DHE suites, or use the OpenSSL backend\. **LibreSSL legacy verifier**— 3\.2\.x or 3\.3\.2–3\.3\.6 <= 6\.1\.0 `VERIFY\_PEER=1`and`VERIFY\_ISSUER=0`\. An over\-depth client chain is accepted\. Enable`VERIFY\_ISSUER=1`with a trusted CA bundle, or use OpenSSL / LibreSSL 4\.x\. ## Background GoAhead is an embedded web server used for device management: routers, switches, printers, gateways, and industrial controls and is deployed in hundreds of millions of devices\. Each finding below affects a specific subset of those deployments, depending on the build and configuration\. GoAhead supports two TLS backends: OpenSSL, the default, and MbedTLS\. The OpenSSL backend also works with compatible libraries such as LibreSSL\. GoAhead takes a compile\-time approach regarding certain configurations: \-`ME\_GOAHEAD\_SSL\_VERIFY\_PEER=1`requires a client certificate\. \-`ME\_GOAHEAD\_SSL\_AUTHORITY`points at a PEM bundle of trusted CAs\. \-`ME\_GOAHEAD\_SSL\_VERIFY\_ISSUER=1`requires the certificate chain to establish issuer trust against that bundle\. \-`ME\_GOAHEAD\_SSL\_REVOKE`points at a PEM\-encoded Certificate Revocation List\. \- The OpenSSL backend sets a chain\-depth limit of 10 \(`VERIFY\_DEPTH`\)\. ## OpenSSL\-compatible builds ![](https://framerusercontent.com/images/hpSvyAUiUW81HqH23INxo9F4GCg.png?width=1186&height=418) GoAhead's OpenSSL backend loads the configured CRL into the certificate store but never enables revocation checking\. Revoked client certificates can therefore complete the mTLS handshake even when issuer verification is enabled\. The CRL is loaded in`sslOpen\(\)`: OpenSSL requires`X509\_V\_FLAG\_CRL\_CHECK`to enable CRL checking\. Loading the file into the store does not set that flag\. Without CRL or OCSP checking enabled,`check\_revocation\(\)`returns success before checking revocation status: GoAhead never sets either CRL flag\. OpenSSL returns success without checking the loaded list\. The application's callback would reject error 23,`X509\_V\_ERR\_CERT\_REVOKED`, through its`default:`branch, but the verifier never generates that error\. On GoAhead 6\.1\.0 with OpenSSL 3\.6\.2, a revoked CA\-signed client certificate completed the mTLS handshake with issuer verification enabled\. The verification callback reported error 0 throughout the chain: `X509\_STORE\_load\_locations\(\)`succeeds, so startup produces no warning that CRL enforcement is inactive\. **Affected:**GoAhead 3\.4\.5 through 6\.1\.0 using the OpenSSL\-compatible backend with a CRL configured\. The security impact is clearest with`VERIFY\_PEER=1`, a trusted CA bundle, and`VERIFY\_ISSUER=1`: a previously trusted but revoked identity retains access\. When issuer checking is disabled, the CRL defect remains but unknown issuers are already accepted by policy\. **Fix**: 6\.1\.1 now checks after loading the CRL: ## Mbed TLS builds ![](https://framerusercontent.com/images/4BLyEmvMcJXcmZDmMxDNt9DpE80.png?width=1508&height=1024) GoAhead's mbed TLS backend configures the RFC 3526 2048\-bit DH group through`mbedtls\_ssl\_conf\_dh\_param\_bin\(\)`\. The modulus length passed to that function is taken from the generator buffer: The size arguments tell mbed TLS how many bytes to read from each buffer\. The call uses`sizeof\(dhm\_g\)`for both, even though`dhm\_g`is only one byte long\. The length for`dhm\_p`should be`sizeof\(dhm\_p\)`, or 256 bytes\. As a result, mbed TLS reads only the first byte of`dhm\_p`:`0xFF`\(255\)\. The remaining 255 bytes are discarded\. It accepts this value and sends it to the client during the TLS 1\.2 DHE\_RSA handshake: In ServerKeyExchange,`00 01 ff`identifies a one\-byte DH parameter with the value 255\. It should contain the full 256\-byte value\. The broken parameters leave just eight possible shared\-secret values :`01`,`02`,`04`,`08`,`10`,`20`,`40`and`80`in hex\. An observer can try each candidate and identify the correct one by checking whether it decrypts the captured traffic successfully\. In the attached PoC, I managed to reproduce the shared secret after five attempts\. It matched the client's secret, confirming that the same TLS session keys could be derived to decrypt the HTTP exchange\. A passive observer can decrypt captured sessions using the recorded handshake and encrypted application records completely out of band\. Exploitation requires a client that accepts the broken DH parameters\. The tested OpenSSL client rejected them with`DH\_check\_params\_ex: modulus too small`\. Permissive clients, including custom or embedded implementations without a minimum\-size check, can complete a decryptable session\. ECDHE sessions and TLS 1\.3 are unaffected by this configured finite\-field group\. **Affected:**GoAhead 4\.0\.2 through 6\.1\.0 using the mbed TLS backend with TLS 1\.2 DHE\_RSA suites, where the client accepts the parameters\. The typo entered in 2018 during migration to the binary\-parameter API and survived the April 2024 TLS refactor\. Mbed TLS 4\.x removed the`TLS\_DHE\_\*`suites, so this DHE path isn't impacted\. If you see any of these suites in the JA4S logs of your environment, you might be impacted \(eg\.`t120100\_009f\_1ca028f07214`\) A sample query you might want to run \(in Splunk or other\) would look like: replacing 0014 with the curves listed above\. **Fix**: 6\.1\.1 fixed the typo ## LibreSSL builds ![](https://framerusercontent.com/images/9eCRwNjx8S9ZZpdm2apJKC9yN3k.png?width=1786&height=546) Essentially, an attacker can present a certificate chain longer than GoAhead’s limit and still complete the mTLS handshake on an affected build\. LibreSSL reports an issuer error instead of a depth error\. GoAhead accepts that issuer error when issuer checking is disabled\. GoAhead 6\.1\.0 sets a chain\-depth limit of 10 using`SSL\_CTX\_set\_verify\_depth\(sslctx, VERIFY\_DEPTH\)`\. Its verification callback also checks the depth: That check only assigns a depth error when`ok`is true, the reported depth exceeds the limit, and no error is already present\. The callback then classifies the error: Error 20,`UNABLE\_TO\_GET\_ISSUER\_CERT\_LOCALLY`, is tolerated when issuer checking is disabled\. Error 22,`CERT\_CHAIN\_TOO\_LONG`, is rejected\. LibreSSL 3\.2\.x and 3\.3\.2–3\.3\.6 use the legacy X\.509 verifier by default for peer verification\. Its chain\-building loop contains a FIXME comment \(which is what prompted a look at GoAhead in the first place\): The loop stops building the chain without recording the depth error\. The failure later reaches GoAhead as error 20\. With`VERIFY\_ISSUER=0`, the callback accepts it\. On GoAhead 6\.1\.0 linked against LibreSSL 3\.3\.6, a 17\-certificate chain rooted in an attacker\-controlled, self\-signed CA produced the following callback trace: The handshake completed and the resource behind the client\-certificate requirement returned HTTP 200\. The same GoAhead source built against LibreSSL 4\.3\.1 received error 22 at depth 10 and rejected the chain\. With`VERIFY\_ISSUER=0`, ordinary self\-signed certificates are already allowed\. The over\-depth chain bypasses the separate chain\-depth restriction because the verifier reports a tolerated issuer error\. Deployments requiring a trusted client CA reject it\. **Demonstrated configuration:**GoAhead 6\.1\.0 with the LibreSSL legacy verifier,`ME\_GOAHEAD\_SSL\_VERIFY\_PEER=1`, and`ME\_GOAHEAD\_SSL\_VERIFY\_ISSUER=0`\. Enabling issuer trust rejects error 20\. OpenSSL, BoringSSL, AWS\-LC, and LibreSSL 4\.x builds are not exposed to this legacy\-verifier trigger\. ## Conclusion All three findings affect GoAhead's integration with its TLS libraries\. CRL enforcement depends on a verification flag, DH parameters depend on the supplied buffer lengths, and chain\-depth enforcement depends on how verification errors are handled\. None of these defects prevents the affected handshake from completing\. The backend and build configuration determine which defects apply\. LibreSSL builds can inherit both the CRL defect in the OpenSSL\-compatible backend and the legacy verifier's depth issue\. The mbed TLS backend uses a separate verification path but is affected by the DH truncation when a client accepts the parameters\. To find impacted publicly facing servers in your fleet, here are the JA4Scan\-TLS fingerprints that map to the different backends: Server \(GoAhead 6\.1\.x\) JA4Scan\-TLS OpenSSL 3\.6\.2 03100h0s00sn\_1fe27f6025fb\_d06dc4648d2f\_sr00ss537461 LibreSSL 3\.3\.6 03100h0s00s0\_9d52559f55bc\_c64486648d2f\_sr00sc24603c LibreSSL 4\.3\.1 \(depth bypass unaffected\) 03100h0r00s0\_9d52559f55bc\_c64486206461\_sr00scc98ba1 mbedTLS 3\.6\.6 23100h0s01s0\_d7d3025021f4\_0475c5cede0d\_sr0ss02265cf Read the full blog post about JA4Scan here: [https://foxio\.io/blog/introducing\-ja4scan\-active\-server\-fingerprinting\-for\-tls\-and\-quic](https://foxio.io/blog/introducing-ja4scan-active-server-fingerprinting-for-tls-and-quic) ## POC Reproduction code is available at[https://github\.com/FoxIO\-LLC/blog\_poc/tree/main/chooseyourbackend](https://github.com/FoxIO-LLC/blog_poc/tree/main/chooseyourbackend) ## Timeline \- April 22 2026 \- LibreSSL report \- April 27 2026 \- MbedTLS report \- April 30 2026 \- OpenSSL report \- Aug 2 2026 \- GoAhead 6\.1\.1 released \- Oct 12 2026 \- Advisories published \- Oct 26 2026 \- Blog published ## References [GOAHEAD\-SA\-2026\-0004 / CVE\-2026\-115884](https://github.com/embedthis/goahead/security/advisories/GHSA-r392-vqwx-3r4g): mTLS chain\-depth bypass [GOAHEAD\-SA\-2026\-0005](https://github.com/embedthis/goahead/security/advisories/GHSA-fmvx-2xfx-2gq4): MbedTLS DH parameter truncation [GOAHEAD\-SA\-2026\-0006 / CVE\-2026\-115881](https://github.com/embedthis/goahead/security/advisories/GHSA-5m75-xq69-c3c5): OpenSSL CRL checking disabled [GoAhead SSL documentation](https://www.embedthis.com/goahead/doc/users/ssl.html) [OpenSSL verification flags](https://docs.openssl.org/3.6/man3/X509_VERIFY_PARAM_set_flags/) [OpenSSL](https://docs.openssl.org/3.6/man3/X509_STORE_add_cert/)`X509\_STORE\_set\_flags\(3\)` [RFC 3526 \- MODP Diffie\-Hellman groups](https://datatracker.ietf.org/doc/html/rfc3526)

Similar Articles

@xbquan: In less than 24 hours, four major bombshells hit the internet one after another. @grok Have we entered an era of extreme cyber insecurity?! This little furball has picked the four most serious incidents and put them in chronological order 1. 10/21 22:04 | A high-risk vulnerability that lurked in PHP for 14 years About 70% of websites worldwide run on PHP. Two vulnerabilities…

X AI KOLs Following

Four major cybersecurity incidents came to light in less than 24 hours: a high-severity remote code execution vulnerability that had remained hidden in PHP for 14 years (discovered using AI in an OpenAI-led effort, with a patch already released); Node.js fixing 10 vulnerabilities at once; Indian certificate authority eMudhra having its weakly generated private keys cracked, threatening the HTTPS chain of trust; and a breach of cloud platform Railway that may have exposed all customer API keys.