Debian and Ubuntu shipped fixed versions of APT (Advanced Package Tool, the package manager both distributions rely on) on November 4, 2026 to close CVE-2026-109518, a flaw that lets an attacker sitting on the HTTP path between a machine and its package archive swap a package after APT has verified it, and run code as root. For anyone running more than a handful of servers, the practical job is to find out which hosts still carry an old APT, push the update without waiting for the next maintenance window, and take a hard look at how packages actually reach those machines.
The key points of the APT CVE-2026-109518 flaw in 20 seconds
- Max Justicz found the bug; APT maintainer Julian Andres Klode fixed it in advisory APT-2026-11-01 on November 4, 2026.
- An attacker needs a foothold on the HTTP path: the network, a proxy or a mirror.
- Download retries, which the attack depends on, are on by default since Debian 12 and Ubuntu 22.04.
- Canonical rates it high (7.7 out of 10); no known exploitation.
Spanish security site OpenSecurity has published a detailed breakdown of the APT vulnerability (in Spanish) based on the official advisories. Debian’s DSA-6607-1 (Debian Security Advisory) describes the core problem: APT can merge two different package downloads when an HTTP redirect gives them the same URI. When the download is then resumed, APT reuses hard links, and the package that already passed verification can be replaced with something else. That makes it a man-in-the-middle (MITM) attack, and since .deb packages are installed with root privileges, the end result is arbitrary code execution as root.
The prerequisites matter. The attacker has to be able to tamper with HTTP traffic, the client has to follow redirects and retry downloads, and Acquire::Retries must be greater than zero. That setting has defaulted to 3 since APT 2.3.2, the version line behind Debian 12 “bookworm” and Ubuntu 22.04 LTS. Klode’s advisory notes that plenty of user scripts enabled retries on older releases as well, which is why fixes go all the way back to the 1.2 branch. Canonical, the CNA (CVE Numbering Authority) that assigned the CVE (Common Vulnerabilities and Exposures) identifier, scores it 7.7 under CVSS 4.0 (Common Vulnerability Scoring System), and Ubuntu gives it High priority. Klode labels it critical in his own advisory. None of the sources checked as of November 5, 2026 report active exploitation or a public proof of concept.
Finding vulnerable APT versions across a fleet
On a single box, two commands are enough. dpkg-query reports what is installed, and apt-cache policy shows it next to the candidate version offered by the configured repositories:
dpkg-query -W apt
apt-cache policy apt
On an Ubuntu 24.04 container used to test the commands in this article, the output showed Installed: 2.8.3 and Candidate: 2.8.4ubuntu0.1 from noble-security. If no fixed candidate shows up at all, the problem sits upstream of the host: the security repository is missing from its sources, or an internal mirror has not synced yet. For scripted checks, compare versions with Debian’s own ordering rules rather than as plain strings:
v=$(dpkg-query -W -f='${Version}' apt)
dpkg --compare-versions "$v" ge 2.8.4ubuntu0.1 && echo "apt $v fixed" || echo "apt $v VULNERABLE"Code language: PHP (php)
The threshold depends on the release, so take it from the table below. With Ansible, an ad hoc command collects the installed version from a whole inventory group, and a second one shows each host’s candidate:
ansible debian_ubuntu -m ansible.builtin.command -a "dpkg-query -W -f='${Version}' apt"
ansible debian_ubuntu -m ansible.builtin.shell -a "apt-cache policy apt | head -3"Code language: JavaScript (javascript)
Teams that already keep hardening playbooks can drop this check into the same inventory, along the lines of the GitHub playbook for locking down a Linux server with Ansible.
Fixed APT versions by release
| Release | Fixed version | Advisory |
|---|---|---|
| Debian 12 bookworm | 2.6.2 | DLA-4880-1 |
| Debian 13 trixie | 3.0.4 | DSA-6607-1 |
| Debian sid (unstable) | 3.3.6 | No separate advisory |
| Debian forky (testing) | Not fixed yet (3.3.5) as of November 5, 2026 | Waiting to migrate from sid |
| Ubuntu 26.10 | 3.3.3ubuntu0.1 | USN-8996-1 |
| Ubuntu 26.04 LTS | 3.2.1ubuntu0.1 | USN-8996-1 |
| Ubuntu 24.04 LTS | 2.8.4ubuntu0.1 | USN-8996-1 |
| Ubuntu 22.04 LTS | 2.4.15ubuntu0.1 | USN-8996-1 |
| Ubuntu 20.04 LTS | 2.0.12+esm1 (Ubuntu Pro) | USN-8996-1 |
| Ubuntu 18.04 LTS | 1.6.19+esm1 (Ubuntu Pro) | USN-8996-1 |
| Ubuntu 16.04 LTS | 1.2.36+esm1 (Ubuntu Pro) | USN-8996-1 |
| Ubuntu 14.04 LTS | 1.0.1ubuntu2.24+esm4 (Ubuntu Pro) | USN-8996-1 |
A DLA is a Debian LTS Advisory, issued by Debian’s long-term support team, and a USN is an Ubuntu Security Notice. The +esm builds come through ESM (Expanded Security Maintenance) and require an Ubuntu Pro subscription. Upstream has released fixed versions for the 1.2.36, 1.4.12, 1.6.19, 1.8.2.4, 2.0.12, 2.2.5, 2.4.15, 2.6.2, 2.8.4, 3.0.4 and 3.2.1 branches, plus 3.3.6 in sid. Derivative distributions that build their own APT will need to ship their own update.
Rolling out the fix and checking unattended-upgrades
The fix is simply a newer apt package. As a precaution on networks that are not fully trusted, OpenSecurity suggests turning retries off for that one operation with -o. On the Ubuntu 24.04 test system, these two commands took APT from 2.8.3 to 2.8.4ubuntu0.1:
sudo apt-get -o Acquire::Retries=0 update
sudo apt-get -o Acquire::Retries=0 install --only-upgrade aptCode language: JavaScript (javascript)
Across a fleet, a short playbook can upgrade APT alone and report the resulting version per host. Ansible’s apt and package_facts modules need python3-apt available to whichever Python interpreter Ansible uses on the managed node:
- hosts: debian_ubuntu
become: true
tasks:
- name: Upgrade APT only
ansible.builtin.apt:
name: apt
state: latest
only_upgrade: true
update_cache: true
- name: Gather installed packages
ansible.builtin.package_facts:
- name: Report APT version
ansible.builtin.debug:
msg: "{{ inventory_hostname }}: apt {{ ansible_facts.packages['apt'][0].version }}"Code language: JavaScript (javascript)
Hosts with automatic updates should pick up the fix on their own, since it ships through the security pocket. That is worth confirming rather than assuming:
cat /etc/apt/apt.conf.d/20auto-upgrades
apt-config dump APT::Periodic
systemctl list-timers 'apt-daily*'
sudo unattended-upgrade --dry-run --debug 2>&1 | grep -i 'allowed origins'
grep -h ' apt:' /var/log/apt/history.logCode language: PHP (php)
Both values in 20auto-upgrades should be “1”. If apt-config dump shows APT::Periodic::Enable "0", APT’s daily job exits without doing anything; some container images ship that way. On Ubuntu, the dry run should list the release’s -security origin, while Debian defines it through Origins-Pattern in 50unattended-upgrades. Ubuntu 20.04 and older hosts will only receive the fix if Ubuntu Pro is attached. For a deeper look at that setup, see this guide to hardening Debian with unattended upgrades.
HTTP sources, internal mirrors and the stopgap setting
Because the attack relies on tampering with HTTP traffic, it helps to know which sources are not encrypted. Both formats need checking: classic deb lines in sources.list, and deb822 .sources files, where the address lives in the URIs field:
grep -rnE '^s*deb(-src)?s+([[^]]*]s+)?http://' /etc/apt/sources.list /etc/apt/sources.list.d/*.list 2>/dev/null
grep -nE '^URIs:.*http://' /etc/apt/sources.list.d/*.sources 2>/dev/nullCode language: PHP (php)
On the Ubuntu 24.04 test install, ubuntu.sources pointed to both archive.ubuntu.com and security.ubuntu.com over plain HTTP. Repository signatures still do their job, but this bug is precisely about changing a package after verification. Moving to HTTPS narrows the window for an attacker on the local network, although, as OpenSecurity points out, it does nothing against a mirror or proxy that is already malicious. The real fix is the patched APT.
Acquire::Retries=0 as a temporary measure
The official CVE description says the attack requires a non-zero Acquire::Retries value. Building on that condition, OpenSecurity lists setting it to 0 as a stopgap for machines that cannot be patched right away. The trade-off is more failed downloads on flaky links, so the override should come out once the fixed version is installed:
echo 'Acquire::Retries "0";' | sudo tee /etc/apt/apt.conf.d/99-cve-2026-109518-retries
apt-config dump Acquire::Retries
# After upgrading APT:
sudo rm /etc/apt/apt.conf.d/99-cve-2026-109518-retriesCode language: PHP (php)
One trap when auditing: on a default install, apt-config dump Acquire::Retries prints nothing, because the default of 3 is compiled into APT rather than set in a config file. Empty output does not mean retries are off.
Internal mirrors and apt-cacher-ng
The CVE explicitly names a malicious mirror or proxy as an attack vector, which puts that kind of infrastructure squarely in scope. Where an in-house mirror is used, the first step is confirming it has synced the security suites (bookworm-security, trixie-security, noble-security and so on); otherwise apt-cache policy will not offer the fixed candidate to any client. With a caching proxy such as apt-cacher-ng, which listens on port 3142 by default, clients usually talk to it over HTTP. To see which hosts go through a proxy:
apt-config dump | grep -iE 'Acquire::(http|https)::Proxy'Code language: JavaScript (javascript)
The mirror or proxy server is usually a Debian or Ubuntu machine itself and needs its own APT upgraded. It also makes sense to restrict who can write to it and which network segments could place a device between clients and the cache.
Frequently asked questions
How can I tell whether a server runs a vulnerable APT version?
Running apt-cache policy apt and comparing the installed version with the table is enough. The fixed builds are 2.8.4ubuntu0.1 on Ubuntu 24.04, 2.6.2 on Debian 12 and 3.0.4 on Debian 13.
Are Debian 11 or Ubuntu 20.04 affected?
Not in a default configuration, because retries were not enabled by default before APT 2.3.2. Ubuntu still ships fixes for 20.04 through 14.04 via Ubuntu Pro, since many scripts turned the setting on manually.
Is setting Acquire::Retries to 0 enough?
It removes one of the conditions the attack needs, but it is only a temporary measure. The fix is to install the patched APT and then remove the override.
Is CVE-2026-109518 being exploited?
The sources checked as of November 5, 2026 do not report active exploitation or a public proof of concept.
Sources:
- OpenSecurity: Debian y Ubuntu corrigen un fallo en APT que permite colar paquetes vía MITM (in Spanish)
- Julian Andres Klode: APT-2026-11-01 security update
- Debian: DSA-6607-1 apt security update
- Debian LTS: DLA-4880-1 apt security update
- Debian Security Tracker: CVE-2026-109518
- Ubuntu: CVE-2026-109518
- Ubuntu: USN-8996-1 APT vulnerability
