CVE-2026-109518 Debian and Ubuntu APT: Patching, Hunting – ThreatDefence
Skip to content
Security advisories/Debian APT team; Debian; Canonical
HighActive

CVE-2026-109518 in Debian and Ubuntu APT: Patching, Moving Mirrors to HTTPS and Hunting Tampered Package Installs

Anton Guzhevskiy
Anton Guzhevskiy · Principal Product Researcher
Published November 5, 2026

CVE-2026-109518 is a download verification bypass in APT, the package manager on Debian, Ubuntu and their derivatives. An attacker who can tamper with APT’s HTTP traffic, or who runs a malicious mirror or proxy, can replace a package after APT has checked it, and the package then installs as root. It works in the default configuration of Debian 12 and 13 and Ubuntu 22.04 and later, and Ubuntu points at plain HTTP mirrors by default, including in the cloud. No exploitation or public exploit has been reported. Move APT sources to HTTPS first, then update the apt package on every Debian and Ubuntu host, image and build pipeline.

November 5, 2026: Ubuntu has published USN-8996-1, and its CVE page now lists every release from 14.04 to 26.10 as fixed, so the tracker caveat is removed. The Ubuntu 16.04 and 14.04 fixes need the Ubuntu Pro Legacy Support add-on. Added Ubuntu's official update commands with Acquire::Retries=0 from its November 4 blog post. Debian testing is still on vulnerable 3.3.5. The release team has hinted past the test regressions, and 3.3.6 now waits on a riscv64 build and an i386 reproducibility check. No public proof of concept or researcher write-up yet.
November 5, 2026: First published. Debian testing (forky) has no fix in place yet. Max Justicz has not published a technical write-up.
At a glance
SeverityHigh
StatusActive
ExploitedNo exploitation reported and no public proof of concept as of November 5, 2026. CISA's assessment in the CVE record: exploitation none, automatable no, technical impact total. Not in CISA KEV
ProductAPT package manager (apt) on Debian, Ubuntu and derivative distributions
CVEsCVE-2026-109518
Fixed inapt 3.0.4 on Debian 13, 2.6.2 on Debian 12, 2.4.15ubuntu0.1 on Ubuntu 22.04, 2.8.4ubuntu0.1 on Ubuntu 24.04, 3.2.1ubuntu0.1 on Ubuntu 26.04 and 3.3.3ubuntu0.1 on Ubuntu 26.10. Debian testing is still unfixed

On November 4, 2026, APT maintainer Julian Andres Klode published the APT-2026-11-01 security update and rated CVE-2026-109518 critical. Debian shipped fixes the same day in DSA-6607-1 for Debian 13 and DLA-4880-1 for Debian 12, and Canonical published fixed apt packages for every supported Ubuntu release. Max Justicz reported the flaw. He found the 2019 APT redirect bug, CVE-2019-3462, that also gave a network attacker root.

The flaw breaks the guarantee APT is built on. APT downloads packages over plain HTTP on most systems and relies on signed repository indexes and file hashes to catch tampering. CVE-2026-109518 lets an attacker swap the file after APT has checked it, so the signature checks pass and the attacker’s package is installed with root privileges.

Canonical, as the CVE numbering authority, scores it 7.7 High under CVSS 4.0. The score reflects the attacker position the bug needs: control of the HTTP traffic between a host and its mirror, or control of the mirror or proxy itself. The exposure is broad because the precondition, automatic download retries, is on by default from Debian 12 and Ubuntu 22.04 onward, and Ubuntu still configures HTTP mirrors by default.

Affected and fixed versions

CVE CVSS EPSS CISA KEV Fixed in
CVE-2026-109518 7.7 High (v4.0, Canonical) Not yet scored No apt 3.0.4 (Debian 13), 2.6.2 (Debian 12), 2.4.15ubuntu0.1 (Ubuntu 22.04), 2.8.4ubuntu0.1 (Ubuntu 24.04), 3.2.1ubuntu0.1 (Ubuntu 26.04), 3.3.3ubuntu0.1 (Ubuntu 26.10)

CVSS and EPSS from NVD and FIRST, exploitation status from the CISA Known Exploited Vulnerabilities catalog, checked November 5, 2026.

Debian

Release Vulnerable Fixed Advisory
Debian 13 (trixie) 3.0.3 and earlier 3.0.x 3.0.4 DSA-6607-1, November 4, 2026
Debian 12 (bookworm, now LTS) 2.6.1 and earlier 2.6.x 2.6.2 DLA-4880-1, November 4, 2026
Debian unstable (sid) 3.3.5 and earlier 3.3.6 Uploaded November 4, 2026
Debian testing (forky) 3.3.5 No fix yet 3.3.6 awaits migration. The release team has hinted past its test regressions, and it is waiting on a riscv64 build and an i386 reproducibility check
Debian 11 (bullseye) and Debian 10 (buster), Extended LTS only 2.2.x and 1.8.x Upstream 2.2.5 and 1.8.2.4 Freexian ELTS

Debian 11 left LTS on August 31, 2026. Upstream released 2.2.5 and 1.8.2.4 for the Extended LTS branches, which Freexian supports commercially. Those releases are unaffected in their default configuration (see below).

Ubuntu

Release Fixed apt version Channel
Ubuntu 26.10 3.3.3ubuntu0.1 Security pocket, November 4, 2026
Ubuntu 26.04 LTS 3.2.1ubuntu0.1 Security pocket, November 4, 2026
Ubuntu 24.04 LTS 2.8.4ubuntu0.1 Security pocket, November 4, 2026
Ubuntu 22.04 LTS 2.4.15ubuntu0.1 Security pocket, November 4, 2026
Ubuntu 20.04 LTS 2.0.12+esm1 Ubuntu Pro (ESM)
Ubuntu 18.04 LTS 1.6.19+esm1 Ubuntu Pro (ESM)
Ubuntu 16.04 LTS 1.2.36+esm1 Ubuntu Pro (ESM) with the Legacy Support add-on
Ubuntu 14.04 LTS 1.0.1ubuntu2.24+esm4 Ubuntu Pro (ESM) with the Legacy Support add-on

The Ubuntu versions come from USN-8996-1, published November 4, 2026, and from Ubuntu’s CVE page, which lists every release from 14.04 to 26.10 as fixed. The Launchpad publishing history shows the fixed packages reaching the security pocket for 22.04, 24.04, 26.04 and 26.10 at 14:25 UTC on November 4. The fixes for 20.04 and 18.04 need an attached Ubuntu Pro subscription, and those for 16.04 and 14.04 also need the Legacy Support add-on. The Ubuntu development series is still on 3.3.5.

Other distributions that use APT

Any distribution that ships Debian’s or Ubuntu’s apt inherits the flaw, and the CVE record names derivative distributions explicitly. Systems that take the apt package straight from the Debian or Ubuntu archive get the fix with the upstream update. Distributions that build their own apt package need their own update. Kali Linux, for example, moved 3.3.6+kali1 into kali-rolling on November 4. For Linux Mint, Pop!_OS, Raspberry Pi OS, Proxmox VE, Armbian and appliance images built on Debian or Ubuntu, check which apt version the vendor ships and whether it is at or above the fixed version for its base release.

What the update also fixes

The same releases fix several out-of-bounds memory accesses in APT’s .deb, gpgv, DNS SRV and tag-file parsers. Klode describes them as denial-of-service issues for services that parse untrusted .deb files on a privilege boundary, such as PackageKit or aptdaemon. Some out-of-bounds issues in apt-ftparchive remain unfixed, and the maintainer advises against building repositories from untrusted .deb files.

How the attack works

APT checks every downloaded package against a hash listed in the repository’s signed index. Signature checking moved the trust to the signing key, which is why Debian and Ubuntu were comfortable serving packages over plain HTTP. CVE-2026-109518 is a time-of-check to time-of-use flaw in how APT handles the downloaded files on disk.

The CVE record and the maintainer’s notice describe the chain:

  1. A package install or upgrade triggers downloads over HTTP.
  2. The attacker answers with redirects that point two different package downloads at the same address, so APT treats them as one file and links them together on disk with a hard link.
  3. The attacker returns transient HTTP server errors, which make APT retry and resume the download.
  4. When resuming, APT reopened the existing file and wrote into it. Because the file was a hard link to an already verified package, the attacker’s data overwrote that verified file.
  5. dpkg installs the replaced package, and its maintainer scripts run as root.

The fix, commit 22d0b1f1 on the apt 3.0.y branch, makes APT open every target file exclusively. When resuming, it reads the partial data, unlinks the old file and writes a new one, so a hard link can no longer carry a change across to a verified file.

The retry step is the precondition that decides exposure. The attack requires a non-zero Acquire::Retries setting. APT has set it to 3 by default since version 2.3.2, which means Debian 12 and 13 and Ubuntu 22.04 and later are exposed as installed. Debian 11, Ubuntu 20.04 and older releases default to 0 and are exposed only where an administrator or a script has turned retries on.

Who is exposed, in priority order

The attacker needs to sit on the HTTP path between a host and its package source, or to control the source. Rank your hosts by how realistic that position is.

  1. Hosts that install or upgrade packages over HTTP on networks you do not control. Laptops and developer machines on public or hotel Wi-Fi, field devices on shared links, and anything behind a router an attacker may already own. ARP spoofing or DNS poisoning on the local network is enough to intercept plain HTTP.
  2. Hosts that use a caching proxy or internal mirror. An apt-cacher-ng instance, a corporate proxy or a local mirror sits in the path for every client. If an attacker compromises it, they can reach every Debian and Ubuntu host that installs through it. Many organizations keep these on HTTP precisely so the proxy can cache packages.
  3. Build pipelines and container images. CI runners and Docker builds run apt-get install constantly, often on shared build networks. A tampered package lands in the image and ships to every environment that runs it.
  4. Cloud instances on default Ubuntu mirrors. cloud-init’s default configuration points Ubuntu at http://archive.ubuntu.com/ubuntu, and on AWS at regional http://<region>.ec2.archive.ubuntu.com mirrors, all over plain HTTP. The traffic crosses the provider’s network rather than an open LAN, so interception there is harder, but the transport offers no protection if any hop is compromised. cloud-init’s default for Debian is https://deb.debian.org.
  5. Servers in a well-controlled data center on HTTPS sources. HTTPS stops an on-path attacker from injecting redirects and errors. These hosts are still exposed if the HTTPS mirror or proxy they use is itself malicious or compromised, so update them too.

MSPs that maintain Linux fleets, build images or run shared apt caches for clients should treat the cache and the image pipeline as the first systems to fix, because each one reaches many clients at once.

How to check a host

Check the installed apt version and compare it with the fixed version for the release:

. /etc/os-release; echo "$PRETTY_NAME"
dpkg-query -W -f='${Package} ${Version}\n' apt
apt-cache policy apt

Check whether retries are on. A value of 1 or more meets the precondition:

apt-config dump | grep -iE '^Acquire::Retries'

List package sources that use plain HTTP, in both the classic and the deb822 formats:

grep -rnE '^\s*(deb|deb-src)\s+(\[[^]]*\]\s+)?http://|^\s*URIs:.*http://' \
  /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/null

Check for an APT proxy, since every client that uses it depends on its integrity:

apt-config dump | grep -iE 'Acquire::(http|https)::Proxy|Acquire::http::Proxy-Auto-Detect'

Fleet-wide check

On fleets managed with Ansible or another configuration tool, collect the same values everywhere. This one-liner prints the host, release, apt version, retries setting and whether any HTTP source is configured:

printf '%s\t%s\t%s\tretries=%s\thttp_sources=%s\n' "$(hostname)" \
  "$(. /etc/os-release; echo $VERSION_CODENAME)" \
  "$(dpkg-query -W -f='${Version}' apt)" \
  "$(apt-config dump | awk -F'"' '/^Acquire::Retries /{print $2}')" \
  "$(grep -rlE 'http://' /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/null | wc -l)"

Run it inside container images and golden images as well. The apt package in a base image is the version the next build runs.

Check cached packages against the signed index

If a host may have installed packages over HTTP on a hostile network, compare the packages still in APT’s cache with the hashes in the signed index. A mismatch means the file on disk is different from what the repository published. The cache is often cleaned, especially in containers, so an empty result proves nothing.

cd /var/cache/apt/archives || exit 1
for f in *.deb; do
  [ -e "$f" ] || continue
  pkg=$(dpkg-deb -f "$f" Package); ver=$(dpkg-deb -f "$f" Version)
  want=$(apt-cache show "$pkg=$ver" 2>/dev/null | awk '/^SHA256:/{print $2}')
  have=$(sha256sum "$f" | cut -d' ' -f1)
  if [ -z "$want" ]; then echo "UNVERIFIED $f (version no longer in the index)"
  elif ! printf '%s\n' $want | grep -qx "$have"; then echo "MISMATCH $f"
  fi
done

dpkg --verify cannot settle the question on its own. It checks installed files against checksums that ship inside the package, and a tampered package carries the attacker’s checksums.

Mitigation and remediation

Do these in this order. The order matters because the update itself is downloaded by the vulnerable apt.

  1. Move package sources to HTTPS first. The official Debian and Ubuntu archives, the security archives and the cloud regional mirrors all answer over HTTPS. APT supports HTTPS without extra packages since version 1.5. On minimal systems, install ca-certificates. In /etc/apt/sources.list.d/ubuntu.sources or debian.sources, change http:// to https:// in the URIs: lines, or in the deb lines of sources.list on older releases.
  2. Where HTTPS is impractical for now, turn off retries. The CVE record states the attack requires a non-zero Acquire::Retries. Setting it to 0 removes that precondition, at the cost of downloads failing on the first transient error. Remove the setting once the update is in place.
  3. Update apt on every host. Run the update from a trusted network, after step 1 or 2. On Ubuntu 20.04 and older, the fix is in the ESM repositories, which need an attached Ubuntu Pro subscription, and on 16.04 and 14.04 also the Legacy Support add-on. Unattended upgrades pick the fix up on hosts that have them on for the security pocket.
  4. Fix the shared infrastructure. Update apt on mirror servers and caching proxies, move the upstream side of apt-cacher-ng and corporate proxies to HTTPS, and restrict who can administer them.
  5. Rebuild images. Update base images, golden images and AMIs so new instances start on the fixed apt, and add the version check above to image pipelines. For Debian testing, which has no fix yet, use HTTPS sources or set retries to 0 until 3.3.6 migrates.
  6. Keep HTTPS afterward. Signatures protect package content, and this flaw shows the transport still matters. HTTPS also takes away an attacker’s ability to see which packages a host installs.

Commands for steps 1 to 3 on a current Debian or Ubuntu host:

# Step 1: switch deb822 and classic sources to HTTPS (review the diff before applying on custom mirrors)
sudo sed -i.bak 's#http://#https://#g' /etc/apt/sources.list.d/*.sources /etc/apt/sources.list 2>/dev/null

# Step 2, only if HTTPS is impractical: turn retries off until the update is in place
echo 'Acquire::Retries "0";' | sudo tee /etc/apt/apt.conf.d/99-cve-2026-109518

# Step 3: update apt, then confirm the version
sudo apt-get update && sudo apt-get install --only-upgrade apt
dpkg-query -W -f='${Version}\n' apt

# After the update, if step 2 was used
sudo rm /etc/apt/apt.conf.d/99-cve-2026-109518

Third-party repositories may not serve HTTPS. Check apt-get update for errors after the switch and revert those entries individually.

On Ubuntu, Canonical’s November 4 guidance gives its own commands. They turn retries off for that one run, so no configuration file is left behind:

# Check the installed apt version
apt list --installed '?source-package(^apt$)'

# Upgrade everything with retries off for this run
sudo apt update && sudo apt upgrade -o Acquire::Retries=0

# Or upgrade only the packages built from the apt source
sudo apt update && sudo apt install -o Acquire::Retries=0 --only-upgrade '?source-package(^apt$)'

Canonical also publishes a sed command to move the Ubuntu archive entries to HTTPS, warns that some community mirrors do not support HTTPS, and recommends installing the update even on hosts that already use HTTPS. Unattended upgrades, on by default since Ubuntu 16.04, should apply the fix within 24 hours.

Threat hunting

Exploitation needs a run of HTTP redirects and server errors during a package download, then a package install that runs attacker code as root. Hunt for both halves: the download pattern in proxy and network logs, and unexpected behavior from package installs on hosts.

Set expectations about telemetry. APT writes /var/log/apt/history.log, /var/log/apt/term.log and /var/log/dpkg.log to disk, not to syslog, so they reach a SIEM only if you collect them. The best network evidence comes from the proxy or mirror that served the packages. On hosts, Defender for Endpoint on Linux records the processes and files that package installs create.

The KQL below is example code for Microsoft Sentinel and Microsoft Defender for Endpoint. Adapt table and field names to your environment and test each query before relying on it.

Hunt 1: inventory APT clients and their versions from web traffic

APT identifies itself as Debian APT-HTTP/1.3 (<version>), so any proxy or web gateway that logs user agents gives you a fleet-wide apt version inventory and a list of hosts still fetching over HTTP.

// Example: Sentinel ASIM web sessions, APT clients by version and protocol
let fixed = dynamic(["3.0.4", "2.6.2", "3.3.6", "2.2.5", "1.8.2.4",
    "2.4.15ubuntu0.1", "2.8.4ubuntu0.1", "3.2.1ubuntu0.1", "3.3.3ubuntu0.1",
    "2.0.12+esm1", "1.6.19+esm1", "1.2.36+esm1", "1.0.1ubuntu2.24+esm4", "3.3.6+kali1"]);
_Im_WebSession(starttime=ago(14d), endtime=now())
| where HttpUserAgent has "APT-HTTP"
| extend AptVersion = extract(@"APT-HTTP/[\d.]+ \(([^)]+)\)", 1, HttpUserAgent)
| extend Scheme = tostring(parse_url(Url).Scheme), MirrorHost = tostring(parse_url(Url).Host)
| summarize Requests=count(), Mirrors=make_set(MirrorHost, 10), LastSeen=max(TimeGenerated)
    by SrcIpAddr, SrcHostname, AptVersion, Scheme
| extend OnFixedBuild = AptVersion in (fixed)
| order by OnFixedBuild asc, Scheme desc, Requests desc

Rows with OnFixedBuild false and Scheme http are the hosts to fix first. Versions outside the list may be derivative builds, so check them against the vendor before closing them.

Hunt 2: redirects and server errors on package downloads

The attack needs the same client to request package files repeatedly in a short window, with redirects and transient server errors in the responses. Mirrors do fail, so look for the combination on .deb files and rank by how unusual it is for the mirror.

// Example: Sentinel ASIM web sessions, .deb downloads retried after redirects and 5xx errors
_Im_WebSession(starttime=ago(30d), endtime=now())
| where HttpUserAgent has "APT-HTTP" and Url has ".deb"
| extend Status = toint(HttpStatusCode), MirrorHost = tostring(parse_url(Url).Host)
| summarize Requests=count(),
    Redirects=countif(Status between (300 .. 399)),
    ServerErrors=countif(Status between (500 .. 599)),
    Files=dcount(Url), Urls=make_set(Url, 10),
    FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated)
    by SrcIpAddr, SrcHostname, MirrorHost, bin(TimeGenerated, 10m)
| where Redirects > 0 and ServerErrors > 0
| order by ServerErrors desc

Where your proxy logs to CommonSecurityLog instead, the same idea applies with RequestClientApplication, RequestURL and the vendor’s status code field. Redirects to a host outside your approved mirrors deserve a look on their own.

Hunt 3: APT traffic to unexpected hosts

// Example: Sentinel ASIM web sessions, APT requests to hosts outside the approved mirror list
let approved = dynamic(["deb.debian.org", "security.debian.org", "archive.ubuntu.com",
    "security.ubuntu.com", "ports.ubuntu.com", "esm.ubuntu.com"]);
_Im_WebSession(starttime=ago(30d), endtime=now())
| where HttpUserAgent has "APT-HTTP"
| extend MirrorHost = tolower(tostring(parse_url(Url).Host))
| where not(MirrorHost in (approved)
    or MirrorHost endswith ".archive.ubuntu.com" or MirrorHost endswith ".ports.ubuntu.com")
| summarize Requests=count(), Clients=dcount(SrcIpAddr), Sample=any(Url),
    FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated) by MirrorHost, DstIpAddr
| order by Clients desc

Add your internal mirrors, caching proxies and third-party repositories to the approved list. Whatever remains is a host you did not expect APT to talk to.

Hunt 4: apt version on endpoints

// Example: Defender for Endpoint, installed apt package versions on Linux devices
DeviceTvmSoftwareInventory
| where OSPlatform has "Linux" and SoftwareName =~ "apt"
| summarize Devices=dcount(DeviceId), Sample=make_set(DeviceName, 20) by OSPlatform, SoftwareVersion
| order by Devices desc

Compare SoftwareVersion with the fixed version for each release in the tables above.

Hunt 5: package maintainer scripts doing unusual things

A tampered package runs its payload from a maintainer script, a preinst or postinst in /var/lib/dpkg/info/, as root. Legitimate scripts call many tools, so focus on downloads, encoded commands and reverse shells.

// Example: Defender for Endpoint, maintainer scripts starting downloaders, decoders or shells
DeviceProcessEvents
| where Timestamp > ago(30d)
| where InitiatingProcessCommandLine has "/var/lib/dpkg/info/"
    or InitiatingProcessParentFileName =~ "dpkg"
| where FileName in~ ("curl", "wget", "nc", "ncat", "socat", "base64", "python3", "perl", "bash", "sh")
| where ProcessCommandLine has_any ("http://", "https://", "base64 -d", "/dev/tcp/", "nc -e", "| sh", "|sh", "| bash", "chmod +x /tmp", "/dev/shm/")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine,
          InitiatingProcessCommandLine, InitiatingProcessParentFileName
| order by Timestamp desc
// Example: Defender for Endpoint, network connections made during package installation
DeviceNetworkEvents
| where Timestamp > ago(30d)
| where InitiatingProcessCommandLine has "/var/lib/dpkg/info/"
    or InitiatingProcessParentFileName =~ "dpkg"
| where RemoteIPType == "Public"
| summarize Connections=count(), Devices=dcount(DeviceId), Sample=any(InitiatingProcessCommandLine)
    by RemoteIP, RemotePort, RemoteUrl, InitiatingProcessFileName
| order by Devices asc, Connections desc

A connection that appears on one host only, during a package install, is the pattern to chase.

Hunt 6: rare binaries written by dpkg

A replaced package installs files the rest of the world has never seen. Compare files written by dpkg with Microsoft’s global prevalence data.

// Example: Defender for Endpoint, files dpkg wrote into system paths with low global prevalence
DeviceFileEvents
| where Timestamp > ago(30d)
| where InitiatingProcessFileName =~ "dpkg"
| where ActionType in ("FileCreated", "FileModified", "FileRenamed")
| where FolderPath has_any ("/usr/bin/", "/usr/sbin/", "/usr/lib/", "/usr/libexec/", "/etc/systemd/", "/etc/cron")
| where isnotempty(SHA1)
| summarize Devices=dcount(DeviceId), Paths=make_set(FolderPath, 5), FirstSeen=min(Timestamp) by SHA1
| invoke FileProfile(SHA1, 1000)
| where isempty(GlobalPrevalence) or GlobalPrevalence < 50
| project SHA1, Paths, Devices, FirstSeen, GlobalPrevalence, Signer, ThreatName
| order by Devices asc

Locally built packages and internal repositories will appear here. Allow-list them and review the rest.

Hunt 7: package installs outside change windows

// Example: Defender for Endpoint, interactive package installs by host and hour
DeviceProcessEvents
| where Timestamp > ago(30d)
| where FileName in~ ("apt", "apt-get", "aptitude", "dpkg")
| where ProcessCommandLine has_any (" install", " -i ", "--install", " upgrade", "dist-upgrade", "full-upgrade")
| extend Hour = hourofday(Timestamp)
| summarize Runs=count(), Commands=make_set(ProcessCommandLine, 10), Accounts=make_set(AccountName, 5)
    by DeviceName, bin(Timestamp, 1d), OffHours = (Hour < 7 or Hour > 19)
| where OffHours
| order by Timestamp desc

Unattended upgrades run on a timer, so filter out their schedule before reviewing.

Responding to a suspected compromise

  1. Isolate the host from the network while keeping it running, and stop further package operations.
  2. Preserve evidence. Copy /var/log/apt/, /var/log/dpkg.log*, /var/cache/apt/archives/, /var/lib/dpkg/info/, /var/lib/dpkg/status and the APT configuration in /etc/apt/. Record the package sources and proxy in use at the time.
  3. Identify the packages installed in the suspect window from history.log and dpkg.log, then run the cache check above against the signed index.
  4. Check the path. Review the mirror, proxy or cache the host used, and the network it was on. If a shared proxy or mirror is involved, every client that installed through it in that window is in scope.
  5. Rebuild the host. A malicious maintainer script ran as root, so reinstalling packages is not enough. Rebuild from a known-good image with the fixed apt and HTTPS sources.
  6. Rotate the host’s secrets, including SSH host and user keys, service credentials, cloud instance credentials and any tokens stored on disk.
  7. Report it. Australian organizations can report to ASD’s ACSC through cyber.gov.au, and US organizations to CISA.

Detection rules to keep

  • APT user agent with a version below the fixed release for its distribution.
  • APT fetching over plain HTTP from a network outside the corporate perimeter.
  • Redirects and 5xx responses on .deb downloads for the same client within minutes.
  • APT requests to a host outside the approved mirror and repository list.
  • Maintainer scripts in /var/lib/dpkg/info/ starting downloaders, decoders or reverse shells.
  • Public network connections made by processes running under dpkg.
  • Binaries written by dpkg with low global prevalence.

Timeline

  • October 12, 2026: Canonical reserves CVE-2026-109518.
  • October 28 and 29: the fixes are committed to the apt 3.0.y branch, including 22d0b1f1, “methods: Open target files exclusively”.
  • November 2: the APT team tags fixed releases for every maintained branch, from 1.2.36 to 3.2.1, and the Ubuntu 26.10 build 3.3.3ubuntu0.1.
  • November 4, 12:00 UTC: Julian Andres Klode publishes APT-2026-11-01 on the deity mailing list.
  • November 4, 12:07 UTC: Debian publishes DSA-6607-1 for Debian 13. DLA-4880-1 for Debian 12 follows the same day.
  • November 4, 14:25 UTC: fixed apt packages are published to the Ubuntu security pocket for 22.04, 24.04, 26.04 and 26.10.
  • November 4, 15:49 UTC: the CVE record is published with Canonical’s CVSS 4.0 score of 7.7.
  • November 4: apt 3.3.6 is tagged for Debian unstable, and Kali moves 3.3.6+kali1 into kali-rolling.
  • November 4, 17:34 UTC: CISA’s assessment in the CVE record: exploitation none, not automatable, technical impact total.
  • November 4: Ubuntu publishes USN-8996-1 and a blog post with update commands. Its CVE page lists every release from 14.04 to 26.10 as fixed.
  • November 5: Debian testing is still on vulnerable 3.3.5. The release team has hinted 3.3.6 past its test regressions, and migration waits on a riscv64 build and an i386 reproducibility check. No public proof of concept, no researcher write-up, no reported exploitation, no CISA KEV entry and no EPSS score yet.

Frequently Asked Questions

Is CVE-2026-109518 being exploited? No exploitation has been reported as of November 5, 2026, and no public proof of concept is available. CISA’s assessment in the CVE record lists exploitation as none. The CVE is not in CISA’s Known Exploited Vulnerabilities catalog.

Which apt version fixes CVE-2026-109518? apt 3.0.4 on Debian 13, 2.6.2 on Debian 12, 2.4.15ubuntu0.1 on Ubuntu 22.04, 2.8.4ubuntu0.1 on Ubuntu 24.04, 3.2.1ubuntu0.1 on Ubuntu 26.04 and 3.3.3ubuntu0.1 on Ubuntu 26.10. Older Ubuntu LTS releases get ESM builds through Ubuntu Pro, and 16.04 and 14.04 also need the Legacy Support add-on. USN-8996-1 lists every fixed version.

Doesn’t APT verify package signatures? It does, and the flaw gets around that. APT verifies the package, and the attacker then overwrites the verified file through a hard link during a resumed download, before dpkg installs it.

Does using HTTPS mirrors protect against CVE-2026-109518? HTTPS stops an attacker on the network path from injecting the redirects and server errors the attack needs. It does not help if the mirror or proxy you connect to is malicious or compromised, so update apt as well.

Are Ubuntu 20.04 and Debian 11 affected? Their apt versions contain the flaw, but they are unaffected in their default configuration because Acquire::Retries defaults to 0 before apt 2.3.2. They are exposed if retries have been turned on, and fixed builds exist through Ubuntu Pro and Debian Extended LTS.

How do I update apt safely if the update itself downloads over HTTP? Switch the sources to HTTPS, or turn retries off for the update. Canonical’s command for Ubuntu is sudo apt update && sudo apt upgrade -o Acquire::Retries=0. Then install the fixed apt from a network you trust.

Are Docker images and CI builds affected? Yes, wherever they run apt-get with a vulnerable apt. Rebuild base images on the fixed version, and use HTTPS sources in Dockerfiles so builds on shared networks cannot be tampered with.

How ThreatDefence is responding

ThreatDefence is tracking CVE-2026-109518 in our vulnerability intelligence. Where we hold endpoint, proxy and network telemetry, our SOC is:

  • identifying Debian and Ubuntu hosts on unfixed apt versions and those still fetching packages over HTTP
  • watching for redirects and server errors on package downloads, and for APT traffic to unexpected hosts
  • reviewing package installs for maintainer scripts that download, decode or open shells

If you run Linux fleets, shared apt caches or image pipelines and want help with the version sweep or a retrospective hunt, contact us. Read more about our endpoint threat visibility and network detection and response.

Sources

Need help checking your environment for this issue? Talk to the ThreatDefence SOC.Talk to Our SOC

Talk to Our SOC

Questions about this advisory or help checking your environment.

    I'm an MSP, MSSP, or reseller

    By submitting this form, you accept the terms in our privacy policy.