Safeguard
Vulnerability Management•

Has My Distro Shipped the Fix? Checking Debian, Ubuntu, Red Hat and Alpine Security Data for Any CVE

Upstream fix versions don't tell you whether your distribution has shipped the fix, because Debian, Ubuntu and Red Hat backport fixes into the versions they already ship. Where each distribution publishes fix status, what it means, and a script that checks all four for any CVE.

Safeguard Security Team
Security Research
9 min read

When a vulnerability is fixed upstream, the question most teams actually need answered is narrower: has my distribution shipped the fix in the package I run? The upstream version number won't tell you. Debian, Ubuntu and Red Hat backport security fixes into the version they already ship, so a RHEL 9 Libreswan "4.15" can contain a fix that upstream only released in 5.3.2. Answering the question means reading the distribution's own security data.

This guide is for engineers who run Linux servers or build container images on distribution packages. It covers where each major distribution publishes fix status, what their status values mean, a script that checks Debian, Ubuntu, Red Hat and Alpine for any CVE in one go, and what this week's data shows about how differently they move.

The short answer

Don't compare your package version with the upstream fixed version. Check the distribution's security data for the CVE: Debian's security tracker, Ubuntu's CVE tracker (both mirrored into OSV as DEBIAN-CVE-* and UBUNTU-CVE-* records), Red Hat's security data API, and Alpine's secdb. On the host itself, the package changelog is the final word. For the same CVE, distributions can be weeks apart. On 14 October, Alpine had shipped this week's Libreswan fix in every supported branch while Debian, Ubuntu and RHEL had not, and a July Libreswan fix still hadn't reached Debian stable or any Ubuntu LTS release.

Why version numbers mislead

Stable distributions freeze a version and then patch it. Red Hat fixed July's Libreswan CVE-2026-14957, which upstream fixed in 5.3.2, in packages called libreswan-4.12-2.el8_10.6 (RHEL 8) and libreswan-4.15-10.el9_8 (RHEL 9). A scanner that compares 4.15 with 5.3.2 reports a vulnerability that has already been fixed. The reverse mistake matters more. A version that looks new enough upstream can still lack a fix the distribution hasn't backported, and only distribution data says so.

The release suffix is where the fix lives: -10.el9_8 in RPMs, -2.5 or +deb12u2 in Debian packages, -r0 in Alpine. That's why serious container and host scanners read distribution security feeds rather than upstream advisories for OS packages.

Where each distribution publishes it

DistributionSourcePer-CVE status valuesNotes
Debiansecurity-tracker.debian.org, also as OSV DEBIAN-CVE-* recordsopen, resolved (with fixed version), not-affected, plus no-dsa and unimportant notesThe full JSON export covers every package and is large. OSV is easier per CVE
Ubuntuubuntu.com/security/cves, also as OSV UBUNTU-CVE-* recordsneeds-triage, needed, deferred, released, not-affected, ignoredIncludes Ubuntu Pro releases for older LTS versions
Red HatSecurity data API, access.redhat.com/hydra/rest/securitydata/cve/<CVE>.json, plus CSAF/VEX filesaffected_release lists shipped errata (RHSA). package_state gives Affected, Not affected, Will not fix, Fix deferred, Out of support scopeCovers RHEL, OpenShift and layered products
Alpinesecdb.alpinelinux.org per branch and repository (main, community)Lists fixes only: a CVE appears under the package release that fixed it, or under 0 if Alpine was never affectedNo entry means no fix recorded, not "safe"

Check any CVE across all four

This script queries OSV for Debian and Ubuntu, the Red Hat API, and Alpine's secdb for the main and community repositories of the newest branches, and prints one status line per release:

#!/usr/bin/env python3
"""Has my distribution shipped the fix? For each CVE, show per-release fix status
from Debian and Ubuntu (via OSV's DEBIAN-CVE / UBUNTU-CVE records), Red Hat (its
security data API) and Alpine (secdb). Distros backport fixes into old version
numbers, so compare against these, not against the upstream fixed version.
Usage: python3 distro_fix_status.py CVE-2026-94453 [CVE-...]"""
import json, sys, urllib.error, urllib.request

ALPINE = ["v3.23", "v3.24", "edge"]

def get(url):
    try:
        with urllib.request.urlopen(urllib.request.Request(url, headers={"User-Agent": "distro-fix"}), timeout=60) as r:
            return json.load(r)
    except urllib.error.HTTPError as e:
        if e.code == 404:
            return None
        raise

alpine = {f"{b}/{repo}": get(f"https://secdb.alpinelinux.org/{b}/{repo}.json") for b in ALPINE for repo in ("main", "community")}

def osv_distro(prefix, cve):
    rec = get(f"https://api.osv.dev/v1/vulns/{prefix}-{cve}")
    if not rec:
        return ["  no record"]
    out = []
    for a in rec.get("affected", []):
        fixed = [e["fixed"] for r in a.get("ranges", []) for e in r.get("events", []) if "fixed" in e]
        rel = a["package"]["ecosystem"].split(":", 1)[1]
        out.append(f"  {rel:<16} {a['package']['name']:<14} {'fixed in ' + fixed[0] if fixed else 'NO FIX YET'}")
    return out or ["  record has no affected packages"]

def redhat(cve):
    d = get(f"https://access.redhat.com/hydra/rest/securitydata/cve/{cve}.json")
    if not d:
        return ["  no record"]
    out = [f"  {r['product_name'][:40]:<40} fixed by {r.get('advisory')} ({r.get('package')})" for r in d.get("affected_release", [])]
    out += [f"  {p['product_name'][:40]:<40} {p.get('package_name') or '':<14} {p.get('fix_state')}" for p in d.get("package_state", [])]
    return [f"  severity: {d.get('threat_severity')}"] + (out or ["  no product entries"])

def alpine_status(cve):
    out = []
    for branch, db in alpine.items():
        hits = [(p["pkg"]["name"], v) for p in (db or {}).get("packages", [])
                for v, ids in p["pkg"].get("secfixes", {}).items() if cve in ids]
        for name, v in hits:
            out.append(f"  {branch:<16} {name:<14} {'not affected' if v == '0' else 'fixed in ' + v}")
        if not hits:
            out.append(f"  {branch:<16} (not listed: no fix recorded, or not packaged here)")
    return out

for cve in sys.argv[1:]:
    print(f"\n{cve}")
    for name, lines in (("Debian", osv_distro("DEBIAN", cve)), ("Ubuntu", osv_distro("UBUNTU", cve)),
                        ("Red Hat", redhat(cve)), ("Alpine", alpine_status(cve))):
        print(f" {name}")
        for line in lines:
            print(line)

Run on 14 October for this week's Libreswan use-after-free and OpenVPN's NUL-byte certificate bug:

$ python3 distro_fix_status.py CVE-2026-94453 CVE-2026-84790
CVE-2026-94453
 Debian
  12               libreswan      NO FIX YET
  13               libreswan      NO FIX YET
  14               libreswan      NO FIX YET
 Ubuntu
  no record
 Red Hat
  severity: Important
  Fast Datapath for RHEL 9                 libreswan      Affected
  Red Hat Enterprise Linux 10              libreswan      Affected
  Red Hat Enterprise Linux 6               libreswan      Out of support scope
  Red Hat Enterprise Linux 7               libreswan      Affected
  Red Hat Enterprise Linux 8               libreswan      Affected
  Red Hat Enterprise Linux 9               libreswan      Affected
  Red Hat OpenShift Container Platform 4   libreswan      Affected
  Red Hat OpenShift Container Platform 4   openshift/ose-rhel-coreos-9 Affected
 Alpine
  v3.23/main       (not listed: no fix recorded, or not packaged here)
  v3.23/community  libreswan      fixed in 5.3.3-r0
  v3.24/main       (not listed: no fix recorded, or not packaged here)
  v3.24/community  libreswan      fixed in 5.3.3-r0
  edge/main        (not listed: no fix recorded, or not packaged here)
  edge/community   libreswan      fixed in 5.3.3-r0

CVE-2026-84790
 Debian
  12               openvpn        NO FIX YET
  13               openvpn        NO FIX YET
  14               openvpn        fixed in 2.7.8-1
 Ubuntu
  Pro:14.04:LTS    openvpn        NO FIX YET
  Pro:16.04:LTS    openvpn        NO FIX YET
  Pro:18.04:LTS    openvpn        NO FIX YET
  20.04:LTS        openvpn        NO FIX YET
  22.04:LTS        openvpn        NO FIX YET
  24.04:LTS        openvpn        NO FIX YET
  26.04:LTS        openvpn        NO FIX YET
 Red Hat
  no record
 Alpine
  v3.23/main       (not listed: no fix recorded, or not packaged here)
  v3.23/community  (not listed: no fix recorded, or not packaged here)
  v3.24/main       (not listed: no fix recorded, or not packaged here)
  v3.24/community  (not listed: no fix recorded, or not packaged here)
  edge/main        (not listed: no fix recorded, or not packaged here)
  edge/community   (not listed: no fix recorded, or not packaged here)

What this week's data shows

The same three CVEs, summarised:

CVE (upstream fix date)DebianUbuntuRed HatAlpine
Libreswan CVE-2026-94453 (5 Oct)No fix in 12, 13 or 14No record yetAffected on RHEL 7 to 10, no erratumFixed in 5.3.3-r0 on v3.23, v3.24 and edge
OpenVPN CVE-2026-84790 (7 Oct)Fixed in 14 (2.7.8-1) onlyNo fix in any listed LTSNo record (not a RHEL package)No fix recorded
Libreswan CVE-2026-14957 (15 Jul)Fixed in 14 (5.2-2.5) onlyNo fix in 18.04 to 26.04Errata for RHEL 8, 9 and 10, including EUS streamsFixed (5.3.2-r0 or 5.3.3-r0)

Three things stand out. Rolling and fast-moving releases (Alpine, Debian testing) pick up upstream versions quickly. Stable releases wait for a backport. And three months after July's Libreswan fix, Debian stable and every Ubuntu LTS still showed no fixed package, while Red Hat had shipped errata across its supported streams. None of that is visible from the upstream advisory, and your scanner only knows if it reads these feeds.

On the host: read the changelog

Tracker data tells you what has shipped. The changelog on the machine tells you what is installed:

# RPM-based (RHEL, Fedora, Rocky, Alma)
rpm -q --changelog libreswan | grep -E 'CVE-2026-(94453|14957)'

# Debian and Ubuntu
zgrep -E 'CVE-2026-(94453|14957)' /usr/share/doc/libreswan/changelog.Debian.gz

# Alpine (the package's secfixes are recorded in secdb; check the installed release)
apk version libreswan

If the CVE ID appears in the changelog of the installed package, the fix is in, whatever the version number says. Most distributions mention CVE IDs in changelog entries for security uploads, so a script can check this across a fleet.

What to do when your distribution lags

  1. Apply the upstream workaround first. For Libreswan's use-after-free, listen-tcp=no removes the exposure without any package change.
  2. Check whether the CVE matters to your configuration. Distributions sometimes defer fixes for issues that need a non-default setting. Their trackers often say so in a note.
  3. Watch the tracker entry, not just your scanner. The tracker status changes when the distribution ships or decides on a fix, and it often carries a note explaining a deferral.
  4. For internet-facing services, consider the release you build on. If a component sits on your attack surface, a distribution that moves quickly for that package, or a supported upstream build, may be the better trade than the newest stable release.
  5. Don't silence the finding because the version looks old. Use the changelog check above to tell a backported fix from a missing one.

The fair view

Slower isn't careless. Stable distributions exist so that a security update doesn't also change behaviour, and backporting a fix into an older code base takes engineering time, especially when the fix touches code that has since been refactored. Some CVEs are deliberately left for a point release because the risk is low or depends on non-default settings. What isn't reasonable is assuming the upstream fix date is your fix date. For base images in particular, see how the main options compare in our Alpine vs distroless vs Ubuntu comparison.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.