Libreswan, the IPsec VPN daemon shipped in Red Hat Enterprise Linux, Fedora and Debian, released versions 5.4.1 and 5.3.3 on 5 October 2026 with fixes for four vulnerabilities. Three can be triggered by an unauthenticated peer. The CVE records only appeared on 13 October, and as of 14 October neither Debian nor Red Hat had shipped fixed packages. One of the four bugs exists only because an earlier security fix was incomplete, and two were found by an AI model working with a security consultancy.
This post is for anyone running Libreswan gateways or road-warrior VPNs, especially on RHEL-family or Debian systems. It covers what each bug does and who is exposed, the gap between the upstream release and the distribution packages, a script that checks a host while taking distribution backports into account, and what to do while you wait for vendor packages.
The short answer
Upgrade to Libreswan 5.4.1 or 5.3.3, or apply the patches Libreswan publishes, if your distribution hasn't shipped a fix yet. The most serious bug, CVE-2026-94453, is a use-after-free that an unauthenticated peer can trigger, but only on gateways with IKE over TCP enabled (listen-tcp=yes, which is off by default). Turning that setting off is a complete workaround. Two NULL-pointer crashes (CVE-2026-77206 and CVE-2026-77207) affect every IKEv2 responder from 4.7 to 5.4 and have no configuration workaround. The fourth (CVE-2026-77205) affects only 5.3.0 to 5.3.2 in FIPS mode.
| CVE | What it is | Pre-auth | Affected | Libreswan severity | Workaround |
|---|---|---|---|---|---|
| CVE-2026-94453 | Use-after-free when an IKE-over-TCP client disconnects and another packet arrives for the same tuple | Yes | 4.0 to 5.4 | High | listen-tcp=no |
| CVE-2026-77206 | NULL dereference in the EAP path of the IKEv2 state machine, even with EAP unconfigured | Yes | 4.7 to 5.4 | Medium | None, patch |
| CVE-2026-77207 | NULL dereference when a PKCS#7 CERT payload carries a CRL but no certificates | Yes | 4.7 to 5.4 | Medium | None, patch |
| CVE-2026-77205 | FIPS mode: bogus certificates stay in the NSS cache and lock out real peers with the same serial | Not stated | 5.3.0 to 5.3.2 | Low | Disable FIPS mode |
Fixed in 5.4.1 and 5.3.3 (5 October 2026). Libreswan's advisories credit Vlad Miu (CVE-2026-94453), "Claude by Anthropic, as reported by David Korczynski from ADA Logics Ltd" (CVE-2026-77206 and CVE-2026-77207), and Wojciech Tatarski of TuxCare (CVE-2026-77205).
The use-after-free: IKE over TCP
IKE normally runs over UDP. Libreswan also supports IKE over TCP, for networks that block UDP. That support is off unless listen-tcp=yes is set in config setup.
According to the advisory, when a TCP client closes its connection, Libreswan keeps the IKE state in memory, and that state still holds a pointer to the TCP interface endpoint (st_iface_endpoint) that has just been freed. If another packet then arrives for the same address and port tuple, whether a retransmit or a deliberate one, the daemon uses the dangling pointer and crashes. This happens before the peer has authenticated. Libreswan rates it High and says continued triggering causes denial of service and that "remote code execution could be possible". It doesn't claim a working exploit.
The timeline was quick. The project was notified on 16 September, gave distributions advance notice on 24 September, and released on 5 October.
Two pre-auth crashes found by an AI model
CVE-2026-77206 is a fall-through in the IKEv2 state machine that dereferences ike->sa.st_eap when it is NULL. The advisory stresses that any IKEv2 connection can reach it, "even if EAP is not configured at all", via a crafted IKE_AUTH packet. It also notes that EAP wasn't functional in 5.3, so anyone who needs EAP should move to 5.4.1.
CVE-2026-77207 comes from two NSS library functions disagreeing about the same data. When Libreswan receives a CERT payload of type CERT_PKCS7_WRAPPED_X509, it first checks the blob with SEC_PKCS7ContainsCertsOrCrls(), then walks it with SEC_PKCS7GetCertificateList(). For a PKCS#7 SignedData that holds a CRL but no certificates, the first function returns true and the second returns NULL, which Libreswan then dereferences. This is a useful pattern to look for in your own code. A guard that checks a slightly different condition from the one the next line relies on passes inputs that the next line can't handle.
Both bugs crash and restart the pluto daemon, and Libreswan says neither allows code execution. Repeated packets keep the VPN down, though. Libreswan was told about both on 5 August.
The credits are a sign of how audits are changing. Both of these came from an AI model used by ADA Logics, and the July advisory for CVE-2026-14957 says the project itself "used Claude to do a security audit of its codebase", which found that bug. Machine-assisted review is now finding real pre-authentication bugs in widely deployed C daemons. It's also producing fixes that need the same scrutiny as any other change, which is the next story.
A fix that broke FIPS mode
CVE-2026-14957, published in July and fixed in 5.3.2, was an assertion failure in FIPS mode. A malformed certificate, for example one whose public-key exponent is zero, made CERT_ExtractPublicKey() return NULL, which tripped an assertion and crashed the daemon.
The fix for it introduced CVE-2026-77205. In add_decoded_cert(), the corrected code rejected the bad certificate but missed a call to CERT_DestroyCertificate(), so the rejected certificate stayed in the NSS cache. Any genuine certificate with the same serial number was then rejected too, until the service restarted. An attacker who knows or guesses a peer's certificate serial can lock that peer out. The advisory recommends using a CA that issues randomised serial numbers, and notes that an attacker could still learn a serial by tricking a peer into connecting to them first. This only affects 5.3.0 to 5.3.2 in FIPS mode. Versions up to 5.2 and 5.4 and later have different code and aren't affected.
That makes 5.3.x a branch where upgrading for one security fix brought in another. A security fix is a code change like any other, and it deserves the same review and testing, especially in error-handling paths that run only on malformed input.
The distribution gap
The upstream fixes are nine days old, but most Libreswan installs come from a distribution, and the distributions hadn't shipped yet when we checked on 14 October:
- Debian's security tracker lists all four new CVEs as open in bookworm (Libreswan 4.10), trixie (5.2), and forky and sid (5.2). CVE-2026-14957 from July is still open in bookworm and trixie too, and resolved only in forky and sid. By version range, CVE-2026-77205 can't affect Debian's 4.10 and 5.2 packages, so expect it to be marked not affected once triaged.
- Red Hat rates CVE-2026-94453 Important and lists RHEL 7, 8, 9 and 10 (and Fast Datapath for RHEL 9) as affected, with no erratum yet. CVE-2026-77206 and CVE-2026-77207 are Moderate, affecting RHEL 8, 9 and 10. CVE-2026-77205 is Low and affects only RHEL 10 and Fast Datapath, the 5.3-based builds. For comparison, July's CVE-2026-14957 has shipped errata, for example RHSA-2026:46398 for RHEL 10.
This is normal for coordinated releases, and distributions got advance notice on 24 September. But it means the action item for most teams isn't "upgrade to 5.4.1". It's to apply the workaround now and watch for your vendor's package.
Check a host
Version numbers alone mislead on distribution systems, because Red Hat and Debian backport fixes without changing the upstream version. This script reads the installed version, checks listen-tcp and FIPS mode, and looks for each CVE ID in the package changelog (rpm or Debian) before calling anything vulnerable. It only reads. Run it as root so it can read the IPsec configuration.
#!/usr/bin/env python3
"""Check a Libreswan host against the October 2026 advisories (CVE-2026-94453,
-77206, -77207, -77205) and July's CVE-2026-14957. Read-only.
Distribution packages backport fixes without changing the upstream version, so the
script also looks for each CVE ID in the package changelog.
Usage: python3 libreswan_oct2026_check.py [--root /] [--version "Libreswan 5.2"] [--changelog FILE]"""
import argparse, glob, gzip, os, re, subprocess
ap = argparse.ArgumentParser()
ap.add_argument("--root", default="/")
ap.add_argument("--version")
ap.add_argument("--changelog")
a = ap.parse_args()
R = lambda p: os.path.join(a.root, p.lstrip("/"))
V = lambda s: tuple(int(x) for x in re.findall(r"\d+", s)[:3])
def run(cmd):
try:
return subprocess.run(cmd, capture_output=True, text=True, timeout=20).stdout
except (OSError, subprocess.TimeoutExpired):
return ""
ver = a.version or run(["ipsec", "--version"])
m = re.search(r"(\d+\.\d+(?:\.\d+)?)", ver or "")
if not m:
raise SystemExit(f"could not read a Libreswan version from {ver!r}")
v = V(m[1])
print(f"Libreswan {m[1]}")
# Changelog: rpm, Debian, or a file you pass in
log = open(a.changelog).read() if a.changelog else run(["rpm", "-q", "--changelog", "libreswan"])
deb = R("/usr/share/doc/libreswan/changelog.Debian.gz")
if not log and os.path.exists(deb):
log = gzip.open(deb, "rt", errors="ignore").read()
conf = ""
for f in [R("/etc/ipsec.conf")] + glob.glob(R("/etc/ipsec.d/*.conf")):
conf += open(f, errors="ignore").read() + "\n"
tcp = bool(re.search(r"^\s*listen-tcp\s*=\s*yes", conf, re.M))
fips = open(R("/proc/sys/crypto/fips_enabled")).read().strip() == "1" if os.path.exists(R("/proc/sys/crypto/fips_enabled")) else False
print(f" listen-tcp=yes: {tcp}; FIPS mode: {fips}; changelog available: {bool(log)}")
FIXED_UPSTREAM = [(5, 3, 3), (5, 4, 1)]
CVES = [ # id, affected-if, exposure condition, note
("CVE-2026-94453", (4, 0, 0) <= v <= (5, 4, 99), tcp, "pre-auth use-after-free over IKE-over-TCP; workaround listen-tcp=no"),
("CVE-2026-77206", (4, 7, 0) <= v <= (5, 4, 99), True, "pre-auth NULL dereference in EAP path, crash/restart"),
("CVE-2026-77207", (4, 7, 0) <= v <= (5, 4, 99), True, "pre-auth NULL dereference on PKCS#7 CERT payload, crash/restart"),
("CVE-2026-77205", (5, 3, 0) <= v <= (5, 3, 2), fips, "FIPS mode: bogus certificates lock out real peers"),
("CVE-2026-14957", (3, 0, 0) <= v <= (5, 3, 1), fips, "FIPS mode with CA certs loaded: assertion crash"),
]
findings = 0
for cve, in_range, exposed, note in CVES:
if v in FIXED_UPSTREAM or (cve != "CVE-2026-14957" and v >= (5, 4, 1)) or not in_range:
status = "not affected by version"
elif cve in log:
status = "fixed (CVE named in package changelog)"
elif not exposed:
status = "vulnerable version, but the required setting is off here"
else:
status = "VULNERABLE"
findings += 1
print(f" {cve}: {status} [{note}]")
print(f"\n{findings} exposed issue(s)" + ("; upgrade to 5.4.1 or 5.3.3, or your distribution's fixed build" if findings else ""))
raise SystemExit(1 if findings else 0)
Here it is against a test root that looks like a Debian bookworm gateway (Libreswan 4.10, IKE over TCP enabled, FIPS off) whose changelog already contains the July fix:
$ python3 libreswan_oct2026_check.py --root fx --version "Libreswan 4.10" --changelog fx/changelog.txt
Libreswan 4.10
listen-tcp=yes: True; FIPS mode: False; changelog available: True
CVE-2026-94453: VULNERABLE [pre-auth use-after-free over IKE-over-TCP; workaround listen-tcp=no]
CVE-2026-77206: VULNERABLE [pre-auth NULL dereference in EAP path, crash/restart]
CVE-2026-77207: VULNERABLE [pre-auth NULL dereference on PKCS#7 CERT payload, crash/restart]
CVE-2026-77205: not affected by version [FIPS mode: bogus certificates lock out real peers]
CVE-2026-14957: fixed (CVE named in package changelog) [FIPS mode with CA certs loaded: assertion crash]
3 exposed issue(s); upgrade to 5.4.1 or 5.3.3, or your distribution's fixed build
We also tested an upstream 5.3.2 build in FIPS mode with TCP off, where it flags CVE-2026-77205 and the two NULL-pointer bugs but treats the use-after-free as mitigated by configuration, and a 5.4.1 build, which comes back clean. The script can't tell whether CA certificates are loaded, which affects CVE-2026-14957. Run ipsec listcacerts to check that.
What to do now
- If you use IKE over TCP, set
listen-tcp=nountil you can upgrade. That fully removes the use-after-free, the only one of the four that the project says might allow code execution. - Patch or upgrade the IKEv2 responders. CVE-2026-77206 and CVE-2026-77207 have no configuration workaround. Use your distribution's package once it ships, or apply Libreswan's patches (published per CVE at
libreswan.org/security/<CVE>/) to your own builds. - On 5.3.x in FIPS mode, upgrade to 5.3.3, and check that your VPN CA issues random serial numbers.
- Alert on pluto restarts and failed peer authentications. Three of the four bugs show up as daemon crashes, and the FIPS lockout shows up as known peers suddenly failing. Repeated restarts on a gateway should page someone, not just appear in a log.
- Track the vendor errata, not just the upstream tag. Subscribe to Red Hat's or Debian's tracker entries for these four CVEs, and re-run the check when a package lands.
The fair view
None of this is a reason to distrust Libreswan. The project fixed four bugs within weeks of the reports, published clear advisories with workarounds and patches for older branches, and credited everyone involved. Three of the four bugs crash the daemon rather than giving an attacker control, and the most serious one needs a non-default setting. The lessons are elsewhere. The time from an upstream release to a package on your gateway is where the risk sits, a security fix can itself introduce a new bug, and AI-assisted review is now finding pre-authentication bugs in mature C code. All three are worth planning for.