← Back to Feed CACHED · 2026-07-01 01:16:38 · CACHE_KEY CVE-2025-32988
CVE-2025-32988 · CWE-415 · Disclosed 2025-07-10

GnuTLS SAN otherName Export Double-Free

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

A librarian who trips on the same book twice, then knocks over the shelf

GnuTLS mishandles ownership in its Subject Alternative Name export logic when a certificate contains an otherName entry with a malformed or invalid type-id OID. The library calls asn1_delete_structure() on an ASN.1 node it does not actually own, and the parent frees the same structure again — classic CWE-415 double-free. The bug is reachable through public GnuTLS APIs whenever an application parses/exports a hostile certificate's SAN extension. Confirmed affected: GnuTLS 3.8.9 and earlier across the 3.x line; distro-patched in Ubuntu (3.8.9-2ubuntu3.1, 3.8.3-1.1ubuntu3.4, 3.7.3-4ubuntu1.7), Debian 12 (3.7.9-2+deb12u5), and RHEL backports.

Vendor MEDIUM (6.5) is roughly fair on paper but *overstated in practice*. The CVSS vector demands AC:H (high complexity — attacker must craft a malformed OID that survives ASN.1 parsing to the exact SAN export path), and impact is scoped to C:N/I:L/A:H — no confidentiality loss, limited integrity, and DoS on whoever is parsing the cert. There is no confirmed RCE primitive in the wild; every advisory reads 'may result in denial of service or memory corruption, depending on allocator behavior'. That's a crash, not a shell.

"A double-free in a rarely-touched X.509 SAN export path. Vendor said MEDIUM; real-world reachability puts this in the backlog."
02 · The Attack Path

3 steps from start to impact.

STEP 01

Craft a malicious X.509 certificate

Attacker builds a certificate whose Subject Alternative Name extension carries an otherName GeneralName with an invalid or malformed type-id OID. This can be produced with openssl asn1parse + a custom ASN.1 editor, or a scripted python-asn1 / pyasn1 generator. The cert must otherwise parse cleanly enough to reach GnuTLS's SAN export routine.
Conditions required:
  • Ability to present a certificate to a GnuTLS-linked target
  • ASN.1 crafting skill
Where this breaks in practice:
  • Malformed OIDs are rejected early by many higher-level validators before reaching the SAN export path
  • No public PoC or exploit tooling released as of assessment date
Detection/coverage: No scanner signature for the crafted cert itself; vulnerability scanners (Tenable, Qualys, Rapid7) flag GnuTLS package version only.
STEP 02

Deliver the certificate to a GnuTLS parser

The attacker must convince a GnuTLS-backed application to *export* SANs from the malicious cert. This is not automatic on every TLS handshake — it happens when code walks gnutls_x509_crt_get_subject_alt_name() / export paths, e.g. cert pinning UIs, mutual-TLS servers that log peer SANs, MTA STARTTLS log pipelines, or CA/PKI tooling.
Conditions required:
  • Target application must invoke the affected SAN export API on attacker-controlled cert data
  • Attacker-controlled TLS endpoint or client cert acceptance
Where this breaks in practice:
  • Most TLS clients rely on GnuTLS's *validation* code path, not the SAN *export* code path
  • mTLS deployments that log SANs are a minority of the install base
  • Modern distros ship hardened glibc allocator (MALLOC_CHECK_, tcache double-free detection) which aborts the process instead of granting exploitation
Detection/coverage: EDR crash telemetry (WER, systemd-coredump, sentry) will surface the abort; no specific IDS rule available.
STEP 03

Trigger the double-free

GnuTLS calls asn1_delete_structure() on the malformed otherName node it does not own; the parent free path frees it again. On glibc, tcache/fastbin double-free detection will typically abort — resulting in a process crash / DoS. In theory, on older allocators or with heap grooming, this could be shaped into arbitrary write, but no such primitive has been publicly demonstrated for this CVE.
Conditions required:
  • Vulnerable GnuTLS ≤ 3.8.9 loaded in the process
  • Allocator without double-free mitigations, OR successful bypass
Where this breaks in practice:
  • glibc 2.29+ tcache double-free detection aborts cleanly
  • systemd auto-restart of most services means DoS is transient
  • Weaponization to RCE would require original research beyond what any advisory documents
Detection/coverage: SIGABRT / coredumps in service logs; correlate with peer cert presentation.
03 · Compensating Control

1
Ride the distro update train — GnuTLS is a base OS library — apply the vendor's monthly patch bundle (apt/dnf/zypper update) as part of routine maintenance. Per noisgate remediation SLA for LOW: no fixed SLA, treat as backlog hygiene, but this will fold in within the next normal patch window on any actively-maintained distro.
2
Restart long-lived GnuTLS-linked services after upgrade — Because GnuTLS is dynamically linked into daemons like Exim, rsyslog (imgtls), BIND, and cups, a package upgrade alone leaves old code resident. Use needrestart -r a (Debian/Ubuntu) or dnf needs-restarting -r (RHEL) to enumerate and restart affected services within the same maintenance window.
3
Constrain mTLS peer cert acceptance where possible — For services that accept client certificates from arbitrary parties (a real reach vector), enforce a trusted issuer whitelist so hostile SAN structures cannot be presented by unauthenticated clients.
4
Verify glibc tcache double-free protection is active — Ensure hosts are on glibc ≥ 2.29 and not running with MALLOC_CHECK_=0 or custom allocators that disable double-free detection. This turns the vuln into a safe abort instead of a corruption primitive.
What doesn't work
  • WAF / TLS inspection appliances — the malformed cert is inside a TLS handshake payload; a WAF sitting at L7 HTTP does not parse peer client certs on inbound mTLS.
  • Certificate transparency / CA revocation — the hostile cert is attacker-issued and never touches a public CA; CT logs and CRLs provide zero coverage.
  • Switching to OpenSSL for the affected app — you may not control the linkage; many packages hard-link GnuTLS. Full rebuild is impractical as a mitigation.
  • IDS signatures on otherName OID — no vendor has shipped such a signature; false-positive rate on legitimate otherName (Kerberos UPN, XmppAddr) would be prohibitive.
04 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo known exploitation. Not on CISA KEV. No incident reports as of 2026-07-01.
Public PoCNone published. No GitHub PoC repos located; no Metasploit / Nuclei template.
EPSS0.01185 (~1.2% probability of exploitation in 30 days) — bottom-half percentile.
KEV statusNot listed.
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H — network-reachable but high attack complexity, no confidentiality impact, availability-dominant.
CWECWE-415 Double Free.
Affected versionsGnuTLS 3.x through 3.8.9. Older 3.7.x branches also affected.
Fixed versionsUbuntu 25.04 3.8.9-2ubuntu3.1, Ubuntu 24.04 3.8.3-1.1ubuntu3.4, Ubuntu 22.04 3.7.3-4ubuntu1.7, Debian 12 3.7.9-2+deb12u5, RHEL backports via RHSA.
Exposure dataGnuTLS ships in virtually every Linux distro but is a *second-tier* TLS library behind OpenSSL — used prominently by GnuPG, Exim, cURL (some builds), rsyslog GTLS module, and BIND-DoT builds.
Disclosed / reported2025-07-10; reported through Red Hat Product Security channels.

Sources.

  1. NVD — CVE-2025-32988
  2. GitHub Advisory GHSA-fv5h-vqpf-6fqj
  3. Wiz Vulnerability Database
  4. SUSE Security Advisory
  5. Snyk — Debian 11 gnutls28
  6. Snyk — CentOS 8 gnutls
  7. SentinelOne CVE writeup
  8. CVEDetails entry
05 · The Call

Final Verdict
↓ DOWNGRADED to LOW (3.5/10)

Why this verdict

  • Impact is DoS, not RCE: every advisory language settles on 'denial of service or memory corruption *depending on allocator behavior*' — modern glibc tcache guards convert the double-free into a clean abort.
  • Reachability is narrow: the bug lives in the SAN *export* path, not the standard validation path. Most TLS clients never invoke gnutls_x509_crt_get_subject_alt_name() on attacker-controlled certs.
  • AC:H is real: attacker must craft an OID that survives outer ASN.1 parsing and lands specifically in the otherName export branch. No off-the-shelf tooling exists.
  • Role multiplier: GnuTLS is not itself a high-value-role component (it's a library, not an IdP/hypervisor/CA/PAM). Even where it's loaded into higher-value processes (e.g., Exim on a mail relay, BIND on a resolver), the chain terminates at that daemon crashing and systemd restarting it — no fleet, identity, or supply-chain pivot.
  • Role multiplier — worst realistic case: GnuTLS embedded in an mTLS-terminating reverse proxy that logs peer SANs. Outcome = repeated proxy crash → localized availability incident, still not fleet-scale. Floor stays at LOW/MEDIUM.
  • No KEV, EPSS ~1.2%: market signal aligns with defender intuition — nobody is racing to exploit this.

Why not higher?

MEDIUM would require credible RCE weaponization or an installed base where mass DoS translates into meaningful business impact. Neither exists: no PoC, no in-the-wild campaigns, and the trigger requires the target application to actively export SANs from an attacker-controlled cert — a narrow slice of GnuTLS consumers.

Why not lower?

IGNORE is inappropriate because the bug is genuine, network-reachable in principle, and lives in ubiquitous TLS plumbing; a determined researcher may still weaponize it against a specific allocator/target. Keep it in the backlog and let normal distro-update cadence resolve it.

06 · Verification

Crowdsourced verification payload.

Run on each target Linux host as a normal user (root not required). Invoke as ./check-cve-2025-32988.sh. It detects installed GnuTLS package version via dpkg/rpm and compares against distro-patched thresholds.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check-cve-2025-32988.sh
# Detect GnuTLS double-free CVE-2025-32988 exposure
# Exit: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

set -u

verdict="UNKNOWN"
detail=""

vercmp() {
  # returns 0 if $1 >= $2 (dpkg style)
  dpkg --compare-versions "$1" ge "$2"
}

if command -v dpkg-query >/dev/null 2>&1; then
  for pkg in libgnutls30 libgnutls30t64 libgnutls28 gnutls28; do
    ver=$(dpkg-query -W -f='${Version}' "$pkg" 2>/dev/null || true)
    [ -z "$ver" ] && continue
    detail="$pkg=$ver"
    # thresholds by codename
    src=$(. /etc/os-release; echo "${VERSION_ID:-}")
    case "$src" in
      25.04) fix="3.8.9-2ubuntu3.1" ;;
      24.04) fix="3.8.3-1.1ubuntu3.4" ;;
      22.04) fix="3.7.3-4ubuntu1.7" ;;
      12)    fix="3.7.9-2+deb12u5" ;;
      *)     fix="" ;;
    esac
    if [ -n "$fix" ]; then
      if vercmp "$ver" "$fix"; then verdict="PATCHED"; else verdict="VULNERABLE"; fi
    fi
    break
  done
elif command -v rpm >/dev/null 2>&1; then
  ver=$(rpm -q --qf '%{VERSION}-%{RELEASE}' gnutls 2>/dev/null | head -1)
  if [ -n "$ver" ]; then
    detail="gnutls=$ver"
    # RHEL backports: check for CVE reference in changelog
    if rpm -q --changelog gnutls 2>/dev/null | grep -q 'CVE-2025-32988'; then
      verdict="PATCHED"
    else
      verdict="VULNERABLE"
    fi
  fi
fi

echo "$verdict ($detail)"
case "$verdict" in
  PATCHED)    exit 0 ;;
  VULNERABLE) exit 1 ;;
  *)          exit 2 ;;
esac