APT Package-Swap RCE as Root on Debian and Ubuntu (CVE-2026-109518)
APT on Debian and Ubuntu can install an attacker's package after a redirect and a retry, giving an on-path attacker root; fixed in 3.3.6 and 3.0.4.
TL;DR
- APT can be made to install a package the attacker supplies instead of the one it verified. A malicious mirror or proxy on the network path triggers it during a package install.
- Debian 12 and later, Ubuntu 22.04 and later, and derivatives that inherit their APT configuration run with package retries enabled by default. Debian 11 and Ubuntu 20.04 are exposed only if retries were turned on.
- Ubuntu rates the flaw CVSS v4.0 7.7 High. CVE-2026-109518 is not in CISA KEV as of November 5, 2026, and no exploitation is known.
- Upgrade APT to the fixed version for your release. If you cannot upgrade yet, set
Acquire::Retries "0"as an interim mitigation; see "How do I fix it?".
Am I affected?
All of these conditions must hold for a system to be exposed:
- APT on the machine is older than the fixed version for its release.
- The machine installs packages through a network path an attacker can modify, such as an HTTP mirror or a proxy.
Acquire::Retriesis non-zero. It defaults to 3 from Debian 12 and Ubuntu 22.04, so older releases are not exposed in a default configuration.- A package install runs while the attacker is on that path, and APT follows a redirect and retries a download.
Debian's and Ubuntu's default archive URLs use HTTP, and an on-path attacker can change the responses. The advisories describe the attack over HTTP. They do not say whether sources reached over HTTPS are exposed. Debian 11 and Ubuntu 20.04 are not affected by default, but user scripts may have enabled retries on them.
| Branch | Affected versions | Fixed version |
|---|---|---|
| Debian unstable (sid) | apt before 3.3.6 | 3.3.6 |
| Debian testing (forky) | apt 3.3.5 and earlier | None yet; 3.3.6 is in unstable |
| Debian 13 (trixie) | apt before 3.0.4 | 3.0.4 (DSA-6607-1) |
| Debian 12 (bookworm) | apt before 2.6.2 | 2.6.2 (DLA-4880-1) |
| Ubuntu 26.10 | apt before 3.3.3ubuntu0.1 | 3.3.3ubuntu0.1 |
| Ubuntu 26.04 LTS | apt before 3.2.1ubuntu0.1 | 3.2.1ubuntu0.1 |
| Ubuntu 24.04 LTS | apt before 2.8.4ubuntu0.1 | 2.8.4ubuntu0.1 |
| Ubuntu 22.04 LTS | apt before 2.4.15ubuntu0.1 | 2.4.15ubuntu0.1 |
| Ubuntu 20.04 LTS | apt before 2.0.12+esm1 | 2.0.12+esm1 (Ubuntu Pro) |
| Ubuntu 18.04 LTS | apt before 1.6.19+esm1 | 1.6.19+esm1 (ESM) |
| Ubuntu 16.04 LTS | apt before 1.2.36+esm1 | 1.2.36+esm1 (ESM) |
| Ubuntu 14.04 LTS | apt before 1.0.1ubuntu2.24+esm4 | 1.0.1ubuntu2.24+esm4 (ESM) |
Debian 11 is past its long-term support window, and the Debian tracker lists no fixed package for it. The CVE record gives 2.2.5 as the first fixed 2.2.x build. Check the installed version:
apt --version
dpkg-query -W -f='${Version}\n' apt
apt --version prints a line such as apt 3.0.3 (amd64). Compare the full installed version with the fixed version for your release: 3.0.3 is older than the fixed 3.0.4. A backport can carry a different version string, so when the version looks older than the table, confirm the distribution's security advisory before concluding the machine is unpatched.
How do I fix it?
Because the upgrade is itself downloaded through APT, apply the mitigation first, then upgrade, then decide whether to keep it.
- Create the retry setting. This removes the retry the attack needs.
bash
printf 'Acquire::Retries "0";\n' | sudo tee /etc/apt/apt.conf.d/99-no-retries
sudo apt-config dump | grep -i 'Acquire::Retries'
The second command prints Acquire::Retries "0"; when the file is read.
- Upgrade APT on Debian:
bash
sudo apt update
sudo apt install --only-upgrade apt
- Upgrade APT on Ubuntu, including the ESM releases where the package is available through Ubuntu Pro:
bash
sudo apt update
sudo apt install --only-upgrade apt
-
Confirm the new version with
apt --version, then repeat on every machine and container image that installs packages. -
Keep
/etc/apt/apt.conf.d/99-no-retriesor remove it after the upgrade. Removing it restores the default retry behaviour and the protection then rests on the fixed APT.
The Debian advisory is DSA-6607-1 and the Ubuntu advisory is USN-8996-1. The fix is the commit "methods: Open target files exclusively".
The workaround limits:
- It prevents APT from retrying a failed download, which is the step the attack needs. The disclosure thread describes it as a mitigation until the upgrade.
- It costs resilience. A transient mirror error now fails the install instead of retrying, so a busy or unreliable mirror will produce more failed runs.
- It does not make the download code safe. The in-place write remains in the binary, and any future path that resumes a download without a retry is not covered.
The workaround covers CVE-2026-109518 only. It does not address the other flaws fixed in the same APT releases.
What is the root cause?
APT is the package manager that resolves dependencies, downloads .deb files and hands them to dpkg. Its HTTP method writes each download to a destination file derived from the request URI. On a resume, it opens that file and writes at an offset.
The vulnerable code opened the destination without an exclusive-create flag. The relevant hunk of methods/http.cc before the fix is:
auto ret = BaseHttpMethod::DealWithHeaders(Res, Req);
if (ret != BaseHttpMethod::FILE_IS_OPEN)
return ret;
if (Req.File.Open(Queue->DestFile, FileFd::WriteAny) == false)
return ERROR_NOT_FROM_SERVER;
Queue->DestFile is the local path for the download. Req.StartPos is the byte offset to resume from. FileFd::WriteAny opens an existing file for writing and creates it when it is missing, but it does not require the file to be new. The open therefore follows an existing directory entry and writes into its inode. A hardlink or a symlink at that path is followed rather than replaced.
Debian's advisory describes the consequence: APT can merge two different package downloads after an HTTP redirect gives them the same URI. Both queues then use one destination file. When one download is resumed, its bytes are written into the file the other queue already verified. The package that dpkg installs is not the package whose hash APT checked.
How is it exploited?
- The attacker takes a position on the path between the APT client and the archive, for example a malicious mirror, a proxy, or a network segment the attacker controls.
- During a package install, the attacker answers a package request with an HTTP redirect whose target URI matches another package download already in APT's queue.
- APT gives the two downloads the same destination file.
- The attacker returns a temporary server error so APT retries the download, which it does by default with
Acquire::Retries 3. - APT reopens the existing destination with
WriteAnyand resumes writing at the previous offset, so the retry's bytes land in the inode that was verified. - The replaced package is installed by
dpkgwith root privileges, and its maintainer scripts run as root.
No public exploit code exists. The steps follow the mechanism in Debian's advisory and the fix commit, not a published proof of concept.
How does the attack flow?
The chain needs an on-path attacker, a redirect that merges two downloads, and a retry that reopens the verified file in place.
malicious mirror or proxy"] --> B["Redirect two package downloads
to one URI"] B --> C["APT reuses one destination file"] C --> D["HTTP error forces a retry"] D --> E["Resume opens the file in place
no exclusive create"] E --> F["Verified package replaced
after the hash check"] F --> G["dpkg installs the attacker's package
as root"]
What can an attacker do?
A successful swap runs arbitrary code as root when the victim installs the replaced package. The package's maintainer scripts execute as root, so the attacker inherits everything root can do on that host.
The impact needs all of these conditions:
- The attacker can modify the HTTP traffic between APT and the archive, or controls a mirror or proxy the victim uses.
- The victim's APT has a non-zero
Acquire::Retries, which is the default from Debian 12 and Ubuntu 22.04. - The attacker can make APT follow a redirect that gives two downloads the same URI.
- A package install runs during the attack, and the attacker can force the retry the resume needs.
An attacker who can already modify the archive traffic can serve a malicious package only if the client accepts it. The signature checks on the repository metadata stop a forged package from an unsigned repository. This flaw bypasses that boundary by replacing a package after APT has verified it. No exploitation in the wild is known, and no public proof of concept exists.
Why does the fix work?
The fix opens every download destination with an exclusive flag. The added code in methods/http.cc is:
// If we are resuming, we first need to rescue the data we already have
FileFd partial;
if (Req.StartPos > 0 && FileExists(Queue->DestFile))
{
if (not partial.Open(Queue->DestFile, FileFd::ReadOnly))
return ERROR_NOT_FROM_SERVER;
}
// Open the file exclusively to avoid injection attacks by links
if (Req.File.Open(Queue->DestFile, FileFd::WriteAny | FileFd::Exclusive) == false)
return ERROR_NOT_FROM_SERVER;
if (partial.IsOpen())
{
// The exclusive open unlinked the old file; copy its content
// into the new one and rewind for hashing.
if (not CopyFile(partial, Req.File) || not partial.Close() || not Req.File.Seek(0))
return ERROR_NOT_FROM_SERVER;
}
FileFd::Exclusive refuses to open an existing file. In this code path APT first reads the partial file through a separate read-only handle. It then creates a new file for the download.
A hardlink or symlink at the destination no longer receives the write. The old directory entry is unlinked and a new inode is created. The resumed bytes are copied into the new file, so the file APT verifies and the file it installs are the same new inode.
The commit applies the same exclusive open to the rred patch method and the store method. It also adds an integration test that downloads onto a hardlink and onto a symlink to a victim file. The test checks that the victim file is unchanged. The fix is complete for the write paths the commit changes. It does not remove the retry behaviour; it makes the resumed write safe.
How do I check if I was compromised?
No indicators of compromise are published. A successful swap leaves the attacker's package installed, and the files and checksums dpkg recorded match that package, so nothing on the machine looks inconsistent. The lead is a mismatch with the official package index, the first of the two checks in this section. An attempt that failed may leave no trace.
Two checks narrow the question:
- For each package APT installed during the exposure window, download the same version from the official archive over HTTPS and compare its file checksums with the ones dpkg recorded at install time.
bash
v=$(dpkg-query -W -f='${Version}' apt)
apt-get download "apt=$v"
dpkg-deb -I apt_*.deb md5sums | diff - /var/lib/dpkg/info/apt.md5sums
Run it with sources that point to the official archive over HTTPS, and repeat it for each package installed in that period. dpkg records the checksums of the files it unpacked, not a hash of the .deb, so a swapped package brings its own matching list.
Any difference from the official package is a lead, because a mirror or proxy may have replaced the file. It is not proof on its own, since a local rebuild also changes the checksums.
- Compare installed versions with the distribution's archive:
bash
apt-cache policy apt
A version that is not in the archive's candidate list is a lead. A replaced package can keep its declared version, so matching versions do not clear the host.
Treat an unexplained checksum or version mismatch on a machine that installed packages over HTTP as a possible compromise. Rebuild the host from a trusted image and rotate the credentials it held.
Timeline
- 2026-10-12: the fix commit "methods: Open target files exclusively" is written and committed, and the CVE is reserved the same day.
- 2026-11-04: CVE-2026-109518 is published at 15:49 UTC. Debian publishes DSA-6607-1 and DLA-4880-1, and Ubuntu publishes USN-8996-1.
- 2026-11-04: Ubuntu publishes fixed APT builds for 26.10, 26.04 LTS, 24.04 LTS and 22.04 LTS to its security archive at 14:25 UTC.
FAQ
Is HTTPS enough to stop this?
The advisories describe the attack over HTTP and do not say whether HTTPS sources are exposed. Use HTTPS mirrors where you can, but do not treat HTTPS as a substitute for the fixed APT package. The flaw is in how the file is written after the download, not only in whether the channel is encrypted.
I run Debian 11 or Ubuntu 20.04. Am I affected?
Not in a default configuration. Acquire::Retries was not the default before Debian 12 and Ubuntu 22.04, and the attack needs a retry. If a script or an administrator enabled retries, the system is exposed. The CVE record lists 2.2.5 as the first fixed 2.2.x build, and Ubuntu 20.04 has 2.0.12+esm1 through Ubuntu Pro.
Can this be exploited without a man-in-the-middle?
No other vector is published. The advisories describe an attacker who can manipulate HTTP traffic, including a malicious mirror or proxy. A local unprivileged attacker who can create a hardlink at the download path is a different threat model, and the test in the fix covers that case too.
Is there a public exploit or exploitation in the wild?
No public proof of concept is published, and no exploitation in the wild is known as of November 5, 2026. CVE-2026-109518 is not in CISA KEV.
Does Acquire::Retries "0" fully fix it?
It removes the retry the attack needs and the disclosure thread describes it as a mitigation until the upgrade. It does not change the in-place write in the binary. Install the fixed APT package as the permanent fix.
Why does Ubuntu rate it 7.7 High when the impact is root code execution?
The CVSS v4.0 base score counts the conditions the attack needs, which are attack requirements present (the redirect and the retry) and passive user interaction (the install). Those reduce the score to 7.7 High while the impact stays high. Ubuntu's own priority for the CVE is High.
References
- Debian, "DSA-6607-1 apt: security update". https://www.debian.org/security/2026/dsa-6607 (checked November 5, 2026)
- Debian, "CVE-2026-109518" security tracker entry, with the fixed packages and the DLA-4880-1 reference. https://security-tracker.debian.org/tracker/CVE-2026-109518 (checked November 5, 2026)
- Debian, "DLA-4880-1 apt: security update". https://security-tracker.debian.org/tracker/DLA-4880-1 (checked November 5, 2026)
- Ubuntu, "USN-8996-1: APT vulnerability". https://ubuntu.com/security/notices/USN-8996-1 (checked November 5, 2026)
- Ubuntu, "CVE-2026-109518". https://ubuntu.com/security/CVE-2026-109518 (checked November 5, 2026)
- CVE Program, "CVE-2026-109518" record, Canonical CNA, published November 4, 2026. https://www.cve.org/CVERecord?id=CVE-2026-109518 (checked November 5, 2026)
- Jan Schaumann, "CVE-2026-109518: RCE in apt(1) (DSA 6607-1)", oss-security, November 4, 2026. https://www.openwall.com/lists/oss-security/2026/11/04/12 (checked November 5, 2026)
- APT, fix commit "methods: Open target files exclusively". https://salsa.debian.org/apt-team/apt/-/commit/5af16a8ad0f155233dfb10b7c92ad1903112ef79 (checked November 5, 2026)