APT: RCE por sustitución de paquete como root en Debian y Ubuntu (CVE-2026-109518)
En Debian y Ubuntu, APT puede instalar un paquete del atacante tras una redirección y un reintento, lo que da root; corregido en 3.3.6 y 3.0.4.
Resumen
- APT puede ser engañado para instalar un paquete que proporciona el atacante en lugar del que verificó. Un espejo o un proxy malicioso en la ruta de red lo desencadena durante la instalación de un paquete.
- Debian 12 y posteriores, Ubuntu 22.04 y posteriores, y las distribuciones derivadas que heredan su configuración de APT tienen los reintentos activados por defecto. Debian 11 y Ubuntu 20.04 solo están expuestos si se activaron los reintentos.
- Ubuntu califica la vulnerabilidad como 7.7 High en CVSS v4.0. CVE-2026-109518 no está en el catálogo KEV de CISA al 5 de noviembre de 2026, y no se conoce explotación.
- Actualice APT a la versión corregida de su distribución. Si no puede actualizar todavía, configure
Acquire::Retries "0"como mitigación provisional; consulte «¿Cómo lo corrijo?».
¿Estoy afectado?
Todas estas condiciones deben cumplirse para que un sistema esté expuesto:
- La versión de APT de la máquina es anterior a la versión corregida de su distribución.
- La máquina instala paquetes a través de una ruta de red que un atacante puede modificar, como un espejo HTTP o un proxy.
Acquire::Retriesno es cero. El valor por defecto es 3 desde Debian 12 y Ubuntu 22.04, por lo que las versiones anteriores no están expuestas en una configuración por defecto.- Se ejecuta una instalación de paquete mientras el atacante está en esa ruta, y APT sigue una redirección y reintenta una descarga.
Las URL de archivo por defecto de Debian y Ubuntu usan HTTP, y un atacante en la ruta puede modificar las respuestas. Los avisos describen el ataque por HTTP. No indican si las fuentes accedidas por HTTPS están expuestas. Debian 11 y Ubuntu 20.04 no están afectados por defecto, pero los scripts de usuario pueden haber activado los reintentos en ellos.
| Rama | Versiones afectadas | Versión corregida |
|---|---|---|
| Debian unstable (sid) | apt anterior a 3.3.6 | 3.3.6 |
| Debian testing (forky) | apt 3.3.5 y anteriores | Ninguna por ahora; 3.3.6 está en unstable |
| Debian 13 (trixie) | apt anterior a 3.0.4 | 3.0.4 (DSA-6607-1) |
| Debian 12 (bookworm) | apt anterior a 2.6.2 | 2.6.2 (DLA-4880-1) |
| Ubuntu 26.10 | apt anterior a 3.3.3ubuntu0.1 | 3.3.3ubuntu0.1 |
| Ubuntu 26.04 LTS | apt anterior a 3.2.1ubuntu0.1 | 3.2.1ubuntu0.1 |
| Ubuntu 24.04 LTS | apt anterior a 2.8.4ubuntu0.1 | 2.8.4ubuntu0.1 |
| Ubuntu 22.04 LTS | apt anterior a 2.4.15ubuntu0.1 | 2.4.15ubuntu0.1 |
| Ubuntu 20.04 LTS | apt anterior a 2.0.12+esm1 | 2.0.12+esm1 (Ubuntu Pro) |
| Ubuntu 18.04 LTS | apt anterior a 1.6.19+esm1 | 1.6.19+esm1 (ESM) |
| Ubuntu 16.04 LTS | apt anterior a 1.2.36+esm1 | 1.2.36+esm1 (ESM) |
| Ubuntu 14.04 LTS | apt anterior a 1.0.1ubuntu2.24+esm4 | 1.0.1ubuntu2.24+esm4 (ESM) |
Debian 11 está fuera de su ventana de soporte a largo plazo, y el seguimiento de Debian no lista ningún paquete corregido para ella. El registro CVE da 2.2.5 como primera compilación corregida de la rama 2.2.x. Compruebe la versión instalada:
apt --version
dpkg-query -W -f='${Version}\n' apt
apt --version imprime una línea como apt 3.0.3 (amd64). Compare la versión instalada completa con la versión corregida de su distribución: 3.0.3 es anterior a la versión corregida 3.0.4. Una retroportación puede llevar una cadena de versión distinta; si la versión parece anterior a la tabla, confirme el aviso de seguridad de la distribución antes de concluir que la máquina no está corregida.
¿Cómo lo corrijo?
Como la actualización también se descarga mediante APT, aplique primero la mitigación, después actualice y luego decida si la mantiene.
- Cree la configuración de reintentos. Esto elimina el reintento que necesita el ataque.
bash
printf 'Acquire::Retries "0";\n' | sudo tee /etc/apt/apt.conf.d/99-no-retries
sudo apt-config dump | grep -i 'Acquire::Retries'
El segundo comando imprime Acquire::Retries "0"; cuando se lee el archivo.
- Actualice APT en Debian:
bash
sudo apt update
sudo apt install --only-upgrade apt
- Actualice APT en Ubuntu, incluidas las versiones ESM donde el paquete está disponible con Ubuntu Pro:
bash
sudo apt update
sudo apt install --only-upgrade apt
-
Confirme la nueva versión con
apt --versiony repita en cada máquina e imagen de contenedor que instale paquetes. -
Mantenga
/etc/apt/apt.conf.d/99-no-retrieso elimínelo después de la actualización. Eliminarlo restaura el comportamiento de reintento por defecto, y la protección queda entonces en el APT corregido.
El aviso de Debian es DSA-6607-1 y el de Ubuntu es USN-8996-1. La corrección es el commit «methods: Open target files exclusively».
Límites de la mitigación:
- Impide que APT reintente una descarga fallida, que es el paso que necesita el ataque. El hilo de divulgación la describe como una mitigación hasta la actualización.
- Cuesta resiliencia. Un error transitorio de un espejo ahora hace fallar la instalación en lugar de reintentar, por lo que un espejo sobrecargado o poco fiable producirá más fallos.
- No hace seguro el código de descarga. La escritura en el lugar sigue en el binario, y cualquier ruta futura que reanude una descarga sin un reintento no está cubierta.
La mitigación cubre solo CVE-2026-109518. No trata las demás vulnerabilidades corregidas en las mismas versiones de APT.
¿Cuál es la causa raíz?
APT es el gestor de paquetes que resuelve dependencias, descarga archivos .deb y los entrega a dpkg. Su método HTTP escribe cada descarga en un archivo de destino derivado de la URI de la petición. En una reanudación, abre ese archivo y escribe en un desplazamiento concreto.
El código vulnerable abría el destino sin un indicador de creación exclusiva. El fragmento correspondiente de methods/http.cc antes de la corrección es:
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 es la ruta local de la descarga. Req.StartPos es el desplazamiento de reanudación en bytes. FileFd::WriteAny abre un archivo existente para escritura y lo crea si falta, pero no exige que el archivo sea nuevo. Por tanto, la apertura sigue una entrada de directorio existente y escribe en su inodo. Un enlace duro o un enlace simbólico en esa ruta se sigue en lugar de reemplazarse.
El aviso de Debian describe la consecuencia: APT puede fusionar dos descargas de paquetes distintas cuando una redirección HTTP les da la misma URI. Las dos colas usan entonces un solo archivo de destino. Cuando una descarga se reanuda, sus bytes se escriben en el archivo que la otra cola ya verificó. El paquete que instala dpkg no es el paquete cuyo hash comprobó APT.
¿Cómo se explota?
- El atacante se sitúa en la ruta entre el cliente APT y el archivo, por ejemplo un espejo malicioso, un proxy o un segmento de red que controla.
- Durante una instalación de paquete, el atacante responde a una petición de paquete con una redirección HTTP cuya URI de destino coincide con otra descarga que ya está en la cola de APT.
- APT da a las dos descargas el mismo archivo de destino.
- El atacante devuelve un error temporal del servidor para que APT reintente la descarga, lo que hace por defecto con
Acquire::Retries 3. - APT reabre el destino existente con
WriteAnyy reanuda la escritura en el desplazamiento anterior, así que los bytes del reintento llegan al inodo que se verificó. dpkginstala el paquete sustituido con privilegios de root, y sus scripts de mantenimiento se ejecutan como root.
No existe código de exploit público. Los pasos siguen el mecanismo descrito en el aviso de Debian y el commit de corrección, no una prueba de concepto publicada.
¿Cómo se desarrolla el ataque?
La cadena necesita un atacante en la ruta, una redirección que fusione dos descargas y un reintento que reabra el archivo verificado en el lugar.
espejo o proxy malicioso"] --> B["Redirección de dos descargas
a una misma URI"] B --> C["APT reutiliza un solo archivo de destino"] C --> D["Un error HTTP fuerza un reintento"] D --> E["La reanudación abre el archivo
en el lugar, sin creación exclusiva"] E --> F["Paquete verificado sustituido
tras la comprobación del hash"] F --> G["dpkg instala el paquete
del atacante como root"]
¿Qué puede hacer un atacante?
Una sustitución correcta ejecuta código arbitrario como root cuando la víctima instala el paquete sustituido. Los scripts de mantenimiento del paquete se ejecutan como root, así que el atacante hereda todo lo que root puede hacer en ese host.
El impacto necesita todas estas condiciones:
- El atacante puede modificar el tráfico HTTP entre APT y el archivo, o controla un espejo o un proxy que usa la víctima.
- El APT de la víctima tiene un
Acquire::Retriesdistinto de cero, que es el valor por defecto desde Debian 12 y Ubuntu 22.04. - El atacante puede hacer que APT siga una redirección que da a dos descargas la misma URI.
- Se ejecuta una instalación de paquete durante el ataque, y el atacante puede forzar el reintento que necesita la reanudación.
Un atacante que ya puede modificar el tráfico del archivo solo puede servir un paquete malicioso si el cliente lo acepta. Las comprobaciones de firma de los metadatos del repositorio impiden que un paquete falsificado venga de un repositorio no firmado. Esta vulnerabilidad elude esa frontera al sustituir un paquete después de que APT lo haya verificado. No se conoce explotación en entornos reales, y no existe una prueba de concepto pública.
¿Por qué funciona la corrección?
La corrección abre cada destino de descarga con un indicador exclusivo. El código añadido en methods/http.cc es:
// 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 se niega a abrir un archivo existente. En esta ruta, APT lee primero el archivo parcial mediante un descriptor de solo lectura. Después crea un archivo nuevo para la descarga.
Un enlace duro o simbólico en el destino ya no recibe la escritura. La entrada de directorio antigua se desvincula y se crea un inodo nuevo. Los bytes reanudados se copian al archivo nuevo, así que el archivo que APT verifica y el que instala son el mismo inodo nuevo.
El commit aplica la misma apertura exclusiva al método de parche rred y al método store. También añade una prueba de integración que descarga sobre un enlace duro y sobre un enlace simbólico a un archivo víctima. La prueba comprueba que el archivo víctima no cambia. La corrección es completa para las rutas de escritura que modifica el commit. No elimina el comportamiento de reintento; hace segura la escritura de reanudación.
¿Cómo compruebo si estuve comprometido?
No se publican indicadores de compromiso. Una sustitución correcta deja instalado el paquete del atacante, y los archivos y sumas de comprobación que registró dpkg coinciden con ese paquete, así que nada en la máquina parece incoherente. La pista es una discrepancia con el índice oficial de paquetes, la primera de las dos comprobaciones de esta sección. Un intento fallido puede no dejar rastro.
Dos comprobaciones acotan la pregunta:
- Para cada paquete que APT instaló durante la ventana de exposición, descargue la misma versión desde el archivo oficial por HTTPS y compare sus sumas de comprobación de archivos con las que dpkg registró en la instalación.
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
Ejecútelo con fuentes que apunten al archivo oficial por HTTPS y repítalo para cada paquete instalado en ese periodo. dpkg registra las sumas de comprobación de los archivos que desempaquetó, no un hash del .deb, así que un paquete sustituido trae su propia lista coherente.
Cualquier diferencia con el paquete oficial es una pista, porque un espejo o un proxy puede haber sustituido el archivo. No es una prueba por sí sola, ya que una reconstrucción local también cambia las sumas de comprobación.
- Compare las versiones instaladas con el archivo de la distribución:
bash
apt-cache policy apt
Una versión que no está en la lista de candidatas del archivo es una pista. Un paquete sustituido puede conservar su versión declarada, así que versiones idénticas no exculpan al host.
Trate una incoherencia inexplicada de suma de comprobación o de versión en una máquina que instaló paquetes por HTTP como una posible compromisión. Reconstruya el host desde una imagen de confianza y rote las credenciales que contenía.
Cronología
- 2026-10-12: se escribe y confirma el commit de corrección «methods: Open target files exclusively», y el CVE se reserva el mismo día.
- 2026-11-04: se publica CVE-2026-109518 a las 15:49 UTC. Debian publica DSA-6607-1 y DLA-4880-1, y Ubuntu publica USN-8996-1.
- 2026-11-04: Ubuntu publica las compilaciones corregidas de APT para 26.10, 26.04 LTS, 24.04 LTS y 22.04 LTS en su archivo de seguridad a las 14:25 UTC.
Preguntas frecuentes
¿Basta HTTPS para bloquear esta vulnerabilidad?
Los avisos describen el ataque por HTTP y no indican si las fuentes HTTPS están expuestas. Use espejos HTTPS cuando pueda, pero no considere HTTPS un sustituto del paquete APT corregido. La vulnerabilidad está en cómo se escribe el archivo después de la descarga, no solo en si el canal está cifrado.
Uso Debian 11 o Ubuntu 20.04. ¿Estoy afectado?
No en una configuración por defecto. Acquire::Retries no era el valor por defecto antes de Debian 12 y Ubuntu 22.04, y el ataque necesita un reintento. Si un script o un administrador activó los reintentos, el sistema está expuesto. El registro CVE da 2.2.5 como primera compilación corregida de la rama 2.2.x, y Ubuntu 20.04 tiene 2.0.12+esm1 con Ubuntu Pro.
¿Se puede explotar sin un atacante en la ruta?
No se publica otro vector. Los avisos describen un atacante que puede manipular el tráfico HTTP, incluido un espejo o un proxy malicioso. Un atacante local sin privilegios que puede crear un enlace duro en la ruta de descarga es otro modelo de amenaza, y la prueba de la corrección también cubre ese caso.
¿Existe un exploit público o explotación en entornos reales?
No se publica ninguna prueba de concepto pública, y no se conoce explotación en entornos reales al 5 de noviembre de 2026. CVE-2026-109518 no está en el catálogo KEV de CISA.
¿Acquire::Retries "0" corrige por completo la vulnerabilidad?
Elimina el reintento que necesita el ataque, y el hilo de divulgación la describe como una mitigación hasta la actualización. No cambia la escritura en el lugar del binario. Instale el paquete APT corregido como solución permanente.
¿Por qué Ubuntu la califica 7.7 High si el impacto es ejecución de código como root?
La puntuación base CVSS v4.0 cuenta las condiciones que necesita el ataque, es decir, requisitos de ataque presentes (la redirección y el reintento) e interacción pasiva del usuario (la instalación). Eso baja la puntuación a 7.7 High mientras el impacto sigue siendo alto. La prioridad de Ubuntu para el CVE es High.
Referencias
- Debian, «DSA-6607-1 apt: security update». https://www.debian.org/security/2026/dsa-6607 (verificado el 5 de noviembre de 2026)
- Debian, entrada «CVE-2026-109518» del seguimiento de seguridad, con los paquetes corregidos y la referencia DLA-4880-1. https://security-tracker.debian.org/tracker/CVE-2026-109518 (verificado el 5 de noviembre de 2026)
- Debian, «DLA-4880-1 apt: security update». https://security-tracker.debian.org/tracker/DLA-4880-1 (verificado el 5 de noviembre de 2026)
- Ubuntu, «USN-8996-1: APT vulnerability». https://ubuntu.com/security/notices/USN-8996-1 (verificado el 5 de noviembre de 2026)
- Ubuntu, «CVE-2026-109518». https://ubuntu.com/security/CVE-2026-109518 (verificado el 5 de noviembre de 2026)
- CVE Program, registro «CVE-2026-109518», CNA Canonical, publicado el 4 de noviembre de 2026. https://www.cve.org/CVERecord?id=CVE-2026-109518 (verificado el 5 de noviembre de 2026)
- Jan Schaumann, «CVE-2026-109518: RCE in apt(1) (DSA 6607-1)», oss-security, 4 de noviembre de 2026. https://www.openwall.com/lists/oss-security/2026/11/04/12 (verificado el 5 de noviembre de 2026)
- APT, commit de corrección «methods: Open target files exclusively». https://salsa.debian.org/apt-team/apt/-/commit/5af16a8ad0f155233dfb10b7c92ad1903112ef79 (verificado el 5 de noviembre de 2026)