A smoke detector screaming because someone left the test button taped down
CVE-2024-5535 is a buffer overread in OpenSSL's SSL_select_next_proto function. When a calling application passes a zero-length client protocol list — a scenario that only arises from a programming error or misconfiguration in the application itself, not from anything an attacker sends — the function returns a pointer to up to 255 bytes of adjacent memory, which may then be transmitted to the remote peer. The flaw affects OpenSSL 1.1.1 through 1.1.1z (fixed in 1.1.1za, available only under premium support), as well as 3.0.x < 3.0.15, 3.1.x < 3.1.7, 3.2.x < 3.2.3, and 3.3.x < 3.3.2. It is associated with NPN (Next Protocol Negotiation), a deprecated predecessor to ALPN that almost no modern application uses.
Tenable inherits an NVD-assigned CVSS base score of 9.1 Critical (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H), which assumes an unauthenticated remote attacker can trivially trigger the bug with no interaction. This is flatly wrong. The OpenSSL project itself rates this Low because the triggering condition — an empty client protocol list — is a local application bug, not something an attacker can inject over the wire. The CVSS vector's AC:L is indefensible; exploitation requires a pre-existing programming error in the consuming application that the attacker does not control. The 9.1 score has caused unnecessary fire drills across thousands of enterprises and should be disregarded.
3 steps from start to impact.
Identify a target using OpenSSL with NPN enabled
- Target application compiled against OpenSSL < 1.1.1za / 3.0.15 / 3.1.7 / 3.2.3 / 3.3.2
- Application uses NPN (deprecated) rather than ALPN
- NPN adoption is near-zero in 2024+ deployments — ALPN is the standard
- Most web servers (nginx, Apache, HAProxy) default to ALPN and do not expose NPN
Application must pass empty client protocol list
SSL_select_next_proto is called with client_len == 0. This is a programming error in the application layer, not a condition an attacker can create by manipulating TLS handshake messages. The attacker would need the application to already contain this bug — essentially, the application must be broken in a specific way before the OpenSSL flaw matters.- Application has a bug that passes zero-length client protocol list to SSL_select_next_proto
- This is an application-layer coding error, not an attacker-controlled input
- No known widely-deployed application has been shown to trigger this path under attacker influence
Memory contents leak to peer
- Steps 1 and 2 both satisfied
- Leaked data is 255 bytes maximum — not targeted, not repeatable in a controlled way
- No code execution, no write primitive, no privilege escalation
The supporting signals.
| In-the-wild exploitation | None observed. Not listed in CISA KEV. No campaign or threat actor has been linked to this CVE. OpenSSL's own assessment is that active exploitation is unlikely because the trigger is not under attacker control. |
|---|---|
| Proof-of-concept | A Python PoC exists at websecnl/CVE-2024-5535 that connects to a target and attempts to trigger the NPN overread. It demonstrates the *behavior* but requires the server-side application to already have the empty-protocol-list bug — the PoC alone cannot force the condition. |
| EPSS score | ~5.58% probability of exploitation in the next 30 days (inflated by CVSS 9.1 base score feeding the model). Percentile is moderate but driven by the misleading base score, not real-world signal. |
| CISA KEV status | Not listed. No known due date or binding directive. |
| CVSS vector | CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H → 9.1. This vector is inaccurate: AC:L should be AC:H at minimum (requires application-level precondition outside attacker control). OpenSSL project rates the flaw Low. |
| OpenSSL project severity | Low — the vendor who wrote the code disagrees with the NVD score by roughly 6 points. |
| Affected versions | OpenSSL 1.1.1–1.1.1z, 3.0.0–3.0.14, 3.1.0–3.1.6, 3.2.0–3.2.2, 3.3.0–3.3.1, 1.0.2–1.0.2zj |
| Fixed versions | 1.1.1za (premium support only), 3.0.15, 3.1.7, 3.2.3, 3.3.2. Distro backports: RHEL, Ubuntu, Debian, SUSE have all shipped fixes. |
| Disclosure date | 2024-06-26 |
| Credit | Reported by the OpenSSL project; PoC by websecnl. |
noisgate verdict.
The single most decisive factor is that the triggering condition — an empty client protocol list passed to SSL_select_next_proto — is a pre-existing application programming error that is not under attacker control, making remote exploitation impractical in any real deployment. OpenSSL's own security team rates this Low, and no evidence of in-the-wild exploitation, KEV listing, or attacker-reachable trigger path contradicts that assessment.
Why this verdict
- Attacker control is absent. The vulnerable code path requires the *calling application* to pass a zero-length client protocol list to
SSL_select_next_proto. This is an application-layer programming error, not a condition an attacker can create by crafting TLS messages. The CVSS vector'sAC:Lis wrong; realistic attack complexity is effectively theoretical. - NPN is dead technology. The flaw is only reachable through NPN (Next Protocol Negotiation), deprecated since RFC 7301 in 2014. ALPN replaced it universally. Finding a production system that uses NPN in 2026 is like finding a fax machine at a startup.
- Impact ceiling is 255 bytes of uncontrolled disclosure. Even if triggered, the attacker gets a small, non-targeted memory fragment. No code execution, no write primitive, no lateral movement, no persistence. This is not a Heartbleed-class leak — there is no ability to repeatedly target specific secrets.
- OpenSSL rates it Low. The vendor that maintains the code — who has every incentive to err on the side of caution — explicitly rates this Low severity. The NVD 9.1 score is a mechanical CVSS calculation that ignores the application-layer precondition.
- Role multiplier: OpenSSL is ubiquitous and runs on high-value infrastructure (load balancers, identity providers, database TLS, edge appliances). However, the attack chain *does not succeed* in any role without a pre-existing application bug that passes empty protocol lists via NPN. No widely-deployed high-value application (nginx, Apache, HAProxy, Node.js, PostgreSQL, etc.) has been shown to contain this specific programming error. The blast radius is therefore not fleet-scale or identity-scale in any realistic deployment, and the role multiplier does not elevate the floor.
Why not higher?
Upgrading to MEDIUM or above would require evidence of a real-world application that exposes the vulnerable code path under attacker-controlled conditions, or evidence of in-the-wild exploitation. Neither exists. The OpenSSL project's own Low rating, the absence from KEV, and the lack of any known campaign all confirm this is not a practically exploitable vulnerability.
Why not lower?
IGNORE would be appropriate only if no affected hosts exist. Since OpenSSL 1.1.1 is still widely deployed (especially on systems that missed the EOL transition), the version-detection finding has hygiene value: it flags hosts running EOL OpenSSL that need to be migrated to 3.x regardless of this specific CVE. The PoC's existence and the theoretical 255-byte leak keep this above zero risk.
What to do — in priority order.
- Confirm your applications use ALPN, not NPN — Audit TLS configurations on all services linked against OpenSSL 1.1.1. If ALPN is in use (it almost certainly is), the vulnerable code path is unreachable. This is a validation step, not a mitigation — but it confirms you can deprioritize. No mitigation SLA applies at LOW severity.
- Prioritize migration off OpenSSL 1.1.1 entirely — OpenSSL 1.1.1 reached public EOL on 2023-09-11. The real risk is not CVE-2024-5535 — it is running an unsupported cryptographic library. Plan migration to OpenSSL 3.x within your standard LOW remediation window (backlog hygiene).
- Apply distro-provided backport patches where available — RHEL, Ubuntu, Debian, and SUSE have all shipped patched versions. Apply during normal patch cycles. No accelerated timeline is needed.
- WAF rules — this is not an HTTP-layer attack; the overread happens inside TLS negotiation and cannot be filtered by a web application firewall.
- TLS version restrictions — disabling TLS 1.0/1.1 does not affect NPN availability; NPN is a TLS extension orthogonal to protocol version.
- Network segmentation — the flaw is triggered by application-internal behavior, not by network-reachable input; segmentation has no effect on the code path.
Crowdsourced verification payload.
Run on each target host where OpenSSL 1.1.1 may be installed. Execute as any user with read access to the openssl binary. Example: bash check_cve_2024_5535.sh or bash check_cve_2024_5535.sh /usr/local/ssl/bin/openssl to specify a non-default path.
#!/usr/bin/env bash
# check_cve_2024_5535.sh — Check for CVE-2024-5535 (OpenSSL SSL_select_next_proto overread)
# Target: Linux/macOS hosts with OpenSSL 1.1.1
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
OPENSSL_BIN="${1:-openssl}"
if ! command -v "$OPENSSL_BIN" &>/dev/null; then
echo "UNKNOWN — openssl binary not found at '$OPENSSL_BIN'"
exit 2
fi
VERSION_STR=$("$OPENSSL_BIN" version 2>/dev/null || true)
if [[ -z "$VERSION_STR" ]]; then
echo "UNKNOWN — could not determine OpenSSL version"
exit 2
fi
echo "Detected: $VERSION_STR"
# Extract version components
if [[ "$VERSION_STR" =~ OpenSSL\ 1\.1\.1([a-z]*) ]]; then
PATCH="${BASH_REMATCH[1]}"
# 1.1.1za is the fix. Patches a-z are vulnerable; za+ are fixed.
if [[ ${#PATCH} -ge 2 ]]; then
echo "PATCHED — $VERSION_STR (>= 1.1.1za)"
exit 0
else
echo "VULNERABLE — $VERSION_STR (< 1.1.1za, affected by CVE-2024-5535)"
exit 1
fi
elif [[ "$VERSION_STR" =~ OpenSSL\ 3\.0\.([0-9]+) ]]; then
MINOR="${BASH_REMATCH[1]}"
if (( MINOR >= 15 )); then
echo "PATCHED — $VERSION_STR (>= 3.0.15)"
exit 0
else
echo "VULNERABLE — $VERSION_STR (< 3.0.15)"
exit 1
fi
elif [[ "$VERSION_STR" =~ OpenSSL\ 3\.1\.([0-9]+) ]]; then
MINOR="${BASH_REMATCH[1]}"
if (( MINOR >= 7 )); then
echo "PATCHED — $VERSION_STR (>= 3.1.7)"
exit 0
else
echo "VULNERABLE — $VERSION_STR (< 3.1.7)"
exit 1
fi
elif [[ "$VERSION_STR" =~ OpenSSL\ 3\.2\.([0-9]+) ]]; then
MINOR="${BASH_REMATCH[1]}"
if (( MINOR >= 3 )); then
echo "PATCHED — $VERSION_STR (>= 3.2.3)"
exit 0
else
echo "VULNERABLE — $VERSION_STR (< 3.2.3)"
exit 1
fi
elif [[ "$VERSION_STR" =~ OpenSSL\ 3\.3\.([0-9]+) ]]; then
MINOR="${BASH_REMATCH[1]}"
if (( MINOR >= 2 )); then
echo "PATCHED — $VERSION_STR (>= 3.3.2)"
exit 0
else
echo "VULNERABLE — $VERSION_STR (< 3.3.2)"
exit 1
fi
elif [[ "$VERSION_STR" =~ OpenSSL\ 3\.[4-9] ]] || [[ "$VERSION_STR" =~ OpenSSL\ [4-9] ]]; then
echo "PATCHED — $VERSION_STR (post-fix branch)"
exit 0
else
echo "UNKNOWN — version '$VERSION_STR' not in the affected range or not recognized"
exit 2
fiIf you remember one thing.
Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.