A parser peeks a few bytes past the end of a certificate extension and hands them back to the caller
GnuTLS mishandles the Certificate Transparency Signed Certificate Timestamp (SCT) extension (OID 1.3.6.1.4.1.11129.2.4.2) during X.509 parsing. A malformed SCT length field lets the library read past the allocated buffer, potentially returning adjacent heap bytes to the calling application. Affected versions cover GnuTLS 3.x prior to 3.8.10; the fix landed in 3.8.10 and Red Hat / Ubuntu / Debian have shipped backports for their respective streams.
The vendor called it MEDIUM (5.3) with vector AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N — low confidentiality only, no integrity, no availability. That's honest. The bug is real and network-triggerable, but it is a *bounded* over-read producing a *low-entropy* leak: no session keys, no RCE primitive, no ASLR bypass path published. The rating matches the impact.
4 steps from start to impact.
Attacker crafts a certificate with a malformed SCT extension
openssl asn1parse, pyasn1, or a fuzzer harness against libgnutls. The certificate can be self-signed — the parser triggers the flaw before signature validation completes.- ability to present a certificate to a GnuTLS-backed client or server
- GnuTLS < 3.8.10 in the parsing path
- most TLS clients terminate early on untrusted issuer before deep extension parsing in a way that reaches the caller
- many stacks strip or ignore the SCT extension unless CT enforcement is on
Attacker delivers the certificate to a GnuTLS peer
curl --cacert against a hostile server is the trivial PoC harness.- network reachability to the GnuTLS peer
- peer completes enough of the handshake to parse extensions
- outbound TLS from servers is often restricted by egress policy
- many callers use OpenSSL not GnuTLS — this only fires where GnuTLS is in the actual parsing path
Parser reads past the SCT buffer
- vulnerable GnuTLS build with SCT parsing reachable
- hardened allocators (glibc
MALLOC_PERTURB_, jemalloc, or Fedora's_FORTIFY_SOURCE=3) can crash the process instead of returning data - ASan/HWASan builds abort immediately
Leaked bytes reach an attacker-observable channel
- calling application echoes parsed cert extension data back over an attacker-observable channel
- the vast majority of GnuTLS callers never surface raw SCT data outward — this is the killer condition
- even when surfaced, entropy of leaked bytes is low; no known session-key or private-key exposure path
The supporting signals.
| In-the-wild status | No known exploitation. Not on CISA KEV. No public campaigns or IR reports reference this CVE. |
|---|---|
| Public PoC | No weaponized PoC published. Reproducers exist inside the GnuTLS test suite and Red Hat Bugzilla but require local library linkage, not a drop-in exploit. |
| EPSS | 0.01179 (~1.2%) — bottom-decile percentile; FIRST models see effectively zero exploit demand. |
| KEV status | Not listed. No CISA action required. |
| CVSS vector | AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N → network-reachable, no auth, but confidentiality-low only; no integrity or availability impact. |
| Affected versions | GnuTLS 3.x prior to 3.8.10 across all distros using upstream branch. |
| Fixed versions | Upstream 3.8.10; RHEL 9 gnutls-3.7.6-x backport, Ubuntu 24.04 3.8.3-1.1ubuntu3.x, Debian bookworm security update — check your distro advisory. |
| Exposure data | Shodan/Censys do not fingerprint GnuTLS version reliably from a handshake; installed base is enormous (default TLS lib on many RHEL/Fedora/embedded builds) but exploit-reachable surface is narrow. |
| Disclosure date | 2025-07-10 via Red Hat Bugzilla and coordinated GnuTLS advisory. |
| Reporter | Reported to Red Hat Product Security; researcher credit in the GnuTLS NEWS file for 3.8.10. |
noisgate verdict.
The decisive factor is impact scope: this is a bounded heap over-read that yields low-entropy adjacent bytes and requires the calling application to surface parsed SCT data back over an attacker-observable channel — a condition rarely met in production. GnuTLS is ubiquitous, but no plausible chain reaches RCE, key extraction, or authentication bypass, so it stays firmly in MEDIUM.
Why this verdict
- Impact is capped at low confidentiality. CVSS
C:L/I:N/A:Nis not vendor sandbagging — the bug reads a bounded number of bytes past a fixed-size buffer with no primitive to pivot to write or execute. - No high-value-role multiplier applies. GnuTLS runs inside identity/PKI-adjacent stacks (LDAP, SASL, CUPS, some VPN clients), but *none* of the affected code paths in those roles surface raw parsed SCT data to the network, so the fleet-scale outcome from role (c) still terminates at a bounded byte leak.
- Exploit demand is near zero. EPSS 0.012, no KEV, no PoC in exploit-DB, no chatter on Trickest/Exploit-DB — attackers are not spending cycles here when they have OpenSSL/NSS memory-safety and Chromium bugs of far higher yield.
- Delivery has friction. The vulnerable SCT parse only fires when the GnuTLS peer actually processes CT extensions on an attacker-controlled cert AND the caller propagates parsed data outward — a two-hop precondition uncommon in shipping products.
Why not higher?
Upgrading to HIGH would require a plausible chain to RCE, key material extraction, or authentication bypass. None exist: the read is bounded, no allocator-state manipulation primitive is published, and there is no session-key adjacency argument. GnuTLS's role in TLS termination is not enough on its own — the bug must actually leak *secret* bytes, and there is no evidence it reliably does.
Why not lower?
Downgrading to LOW would ignore that GnuTLS is a foundational library shipped in RHEL/Fedora/Debian/Ubuntu base images and embedded firmware, and that the attack is unauthenticated and network-triggerable. Any info-disclosure primitive against a TLS parser deserves a real remediation SLA, even if the current leak is small; parser bugs also tend to cluster, and a follow-on write-primitive discovery would sharply raise the stakes.
What to do — in priority order.
- Patch to GnuTLS 3.8.10 (or your distro's backport) — Vendor patches are shipping across RHEL, Ubuntu, Debian, SUSE. No mitigation SLA applies at MEDIUM — plan patch deployment inside the noisgate remediation SLA of ≤ 365 days, but bundle it into your next monthly OS-package cycle since it is a zero-effort update.
- Inventory GnuTLS consumers, not just the library — Enumerate binaries linking
libgnutls.so.30(lsof,ldd, or Snyk/Trivy SBOM scan). Focus especially on outbound TLS clients (CUPS, mailx, socat, wget builds, some VPNs) — those are the paths that touch attacker-controlled certs. Complete inventory within 30 days so your remediation waves are risk-ordered. - Enforce egress TLS to a controlled proxy where feasible — A forward TLS proxy that terminates and re-originates the handshake using OpenSSL or BoringSSL removes GnuTLS from the attacker-cert parsing path for outbound traffic. Applies to the small population of servers making arbitrary outbound TLS calls.
- Disable CT enforcement on GnuTLS clients that don't need it — Applications that call
gnutls_x509_ext_ct_scts_*explicitly can skip the SCT parse path pending patch. Not universally applicable, and CT verification is desirable — treat as a bridge control, not a target state.
- WAF signatures on cert content — the malformed SCT is delivered inside a TLS handshake, before HTTP; the WAF never sees it.
- Certificate pinning on servers you connect to — pinning validates identity, not extension well-formedness; a pinned cert with a malformed SCT still triggers the parser.
- Blocking self-signed certs — the flaw is in extension parsing which runs *before* trust decisions; also, a legitimately-issued cert with a corrupt SCT would still hit the code path.
Crowdsourced verification payload.
Run on each Linux host as root (or any user with read access to /usr/lib*). Invoke as ./check-gnutls-32989.sh. It resolves the linked libgnutls version and compares against the fixed baseline; distro-backported builds are handled by falling back to the package manager version string.
#!/usr/bin/env bash
# noisgate verifier — CVE-2025-32989 (GnuTLS SCT heap over-read)
# Exit: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
FIXED_UPSTREAM="3.8.10"
verlte() { [ "$1" = "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" ]; }
verlt() { [ "$1" != "$2" ] && verlte "$1" "$2"; }
# 1) Try gnutls-cli
if command -v gnutls-cli >/dev/null 2>&1; then
V=$(gnutls-cli --version 2>/dev/null | awk '/gnutls-cli/ {print $NF; exit}')
fi
# 2) Fallback: inspect libgnutls SONAME + package db
if [ -z "${V:-}" ]; then
LIB=$(ldconfig -p 2>/dev/null | awk '/libgnutls\.so\.30/ {print $NF; exit}')
if [ -n "$LIB" ] && command -v strings >/dev/null 2>&1; then
V=$(strings "$LIB" | grep -oE '^3\.[0-9]+\.[0-9]+' | head -n1)
fi
fi
# 3) Package-manager cross-check for distro backports
PKGVER=""
if command -v rpm >/dev/null 2>&1; then
PKGVER=$(rpm -q --qf '%{VERSION}-%{RELEASE}\n' gnutls 2>/dev/null | head -n1)
elif command -v dpkg-query >/dev/null 2>&1; then
PKGVER=$(dpkg-query -W -f='${Version}\n' libgnutls30 2>/dev/null | head -n1)
fi
if [ -z "${V:-}" ] && [ -z "$PKGVER" ]; then
echo "UNKNOWN: GnuTLS not detected"
exit 2
fi
echo "Detected upstream version: ${V:-n/a}"
echo "Detected package version : ${PKGVER:-n/a}"
# Distro backport heuristic: RHEL/Ubuntu ship fixes without bumping upstream to 3.8.10
if [ -n "$PKGVER" ]; then
case "$PKGVER" in
*el9_*|*el8_*|*ubuntu*|*deb12u*|*+deb11u*)
echo "UNKNOWN: distro backport detected — verify against vendor advisory for ${PKGVER}"
exit 2 ;;
esac
fi
if [ -n "${V:-}" ] && verlt "$V" "$FIXED_UPSTREAM"; then
echo "VULNERABLE: GnuTLS $V < $FIXED_UPSTREAM"
exit 1
fi
echo "PATCHED: GnuTLS ${V:-$PKGVER} >= $FIXED_UPSTREAM (or vendor-backported)"
exit 0
If you remember one thing.
apt/dnf update away and it is the easiest CVE you will close this quarter. Monday: run the verifier fleet-wide, generate an SBOM-scoped inventory of everything linking libgnutls.so.30, and fold the update into your next monthly patch train (target 30 days). Skip the WAF / cert-pinning theater — those don't help here.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.