⏱️ Lectura: 9 min

Una qube infectada puede, con un solo intento fallido de copiar un archivo, terminar ejecutando un comando arbitrario en el dominio administrativo de Qubes OS. Así resume el equipo de seguridad del proyecto la falla que corrigió el 28 de agosto de 2026 con el boletín QSB-118.

📑 En este artículo
  1. TL;DR
  2. Qué pasó
  3. Contexto e historia
  4. Detalles técnicos y rendimiento
  5. Cómo protegerte y verificar el parche
  6. Impacto y análisis
  7. Qué sigue
  8. Preguntas frecuentes
    1. ¿Qué es exactamente QSB-118?
    2. ¿Necesito hacer algo además de actualizar dom0?
    3. ¿Por qué la copia del lado de la qube no es vulnerable pero la de dom0 sí?
    4. ¿Cómo confirmo que mi Qubes OS ya tiene el parche?
    5. ¿Esta vulnerabilidad requiere que ya haya un atacante en mi sistema?
  9. Referencias

El problema no está en la copia de archivos en sí, sino en cómo dom0 reporta un error cuando esa copia falla: el nombre del archivo que devuelve la qube de destino termina, sin filtrar del todo, dentro de un comando de shell que corre con privilegios de dom0.

TL;DR

  • QSB-118, publicado el 28 de agosto de 2026, afecta a todas las versiones de Qubes OS
  • Una qube comprometida puede inyectar un comando arbitrario en dom0 vía qvm-copy-to-vm
  • La falla está en sanitize_remote_filename(), que no filtra todos los metacaracteres de shell
  • display_error(), en qfile-dom0-agent.c, arma el diálogo de error con system() sin sanear del todo el nombre
  • La variante del lado de la qube no es vulnerable porque usa execlp() en vez de system()
  • El parche llega en el paquete qubes-core-dom0-linux versión 4.3.22 para Qubes 4.3
  • La vulnerabilidad fue reportada por el investigador identificado como Tim C.
  • Basta actualizar con la herramienta Qubes Update; no hace falta ninguna acción manual extra

Qué pasó

El boletín QSB-118 describe un escenario concreto: si un usuario ejecuta qvm-copy-to-vm desde dom0 para enviar un archivo a una qube que ya está comprometida, esa qube puede devolver una respuesta manipulada que inyecta un comando arbitrario en dom0. El resultado es control total sobre Qubes OS, ya que dom0 es el dominio que administra el resto del sistema.

El propio texto del boletín aclara que no se requiere ninguna acción especial del usuario más allá de actualizar con normalidad: la corrección ya está empaquetada y disponible por los canales habituales de actualización.

Contexto e historia

Qubes OS se basa en compartimentar el sistema en múltiples qubes (máquinas virtuales ligeras) aisladas entre sí, mientras dom0 queda como el dominio privilegiado que administra la GUI, el almacenamiento y el resto de las qubes. Si dom0 se compromete, se compromete todo el sistema; por eso el proyecto trata cualquier ruta de código que exponga a dom0 a datos no confiables como superficie de ataque crítica.

Uno de esos puntos de contacto es qvm-copy-to-vm, que usa el protocolo qfile: un formato de archivo simplificado, más simple que tar o cpio, pensado para transferir archivos entre dom0 y una qube. Al final de la transferencia, el destino le devuelve a dom0 una confirmación con un checksum, un código de error (si lo hay) y el nombre del último archivo recibido. Ese último campo, controlado por la qube de destino, es justamente el que dom0 no terminaba de sanear antes de mostrarlo en un diálogo de error.

Arquitectura de Qubes OS con dom0 y qubes aisladas
Dom0 administra el resto de las qubes: por eso cualquier dato que llega desde una qube es tratado como no confiable. Foto de Logan Gutierrez en Unsplash

Detalles técnicos y rendimiento

La cadena de la falla tiene dos eslabones. El primero es sanitize_remote_filename(), en linux-utils/qrexec-lib/pack.c, que se supone limpia el nombre de archivo antes de mostrarlo:

static void sanitize_remote_filename(char *untrusted_filename)
{
    for (; *untrusted_filename; ++untrusted_filename) {
        if (*untrusted_filename < ' ' ||
            *untrusted_filename > '~' ||
            *untrusted_filename == '"')
            *untrusted_filename = '_';
    }
}

Esta función solo reemplaza caracteres no imprimibles, no-ASCII y comillas dobles por guiones bajos. Todo lo demás, incluidas las comillas simples, los puntos y coma, los signos $() y las barras verticales, pasa intacto.

El segundo eslabón está en core-admin-linux/file-copy-vm/qfile-dom0-agent.c. La función display_error() arma el comando del diálogo de error con asprintf() usando un formato del tipo "%s '%s: %s (error type: %s)'", donde el mensaje completo (que incluye el nombre de archivo ya “saneado”) queda envuelto entre comillas simples, y ese comando se ejecuta con system(), que lo pasa a una shell.

Ahí está el hueco real: como sanitize_remote_filename() nunca toca el carácter comilla simple (0x27), un nombre de archivo que la incluya rompe el contexto de comillas que arma asprintf() y expone al intérprete de shell el resto del texto como código ejecutable.

# Nombre de archivo devuelto por la qube comprometida (ilustrativo):
malicious_name="x'; touch /tmp/dom0-owned; echo '"

# sanitize_remote_filename() no toca la comilla simple, así que
# ese valor llega intacto a display_error() y rompe el string
# entre comillas que se pasa a system(), inyectando el comando
# 'touch /tmp/dom0-owned' con privilegios de dom0.
⚠️ Ojo: construir un comando de shell con asprintf() e interpolar datos no confiables, aunque se envuelvan entre comillas, sigue siendo peligroso si el saneo no cubre exactamente los caracteres que delimitan esas comillas.

La variante que corre del lado de la qube, en core-agent-linux/qubes-rpc/gui-fatal.c, no sufre este problema. En vez de construir un string y pasarlo por system(), hace fork() y luego execlp("/usr/bin/zenity", ...) directamente, sin invocar una shell intermedia que pueda reinterpretar metacaracteres.

VarianteFunción de error¿Vulnerable?Por qué
Dom0 (qfile-dom0-agent.c)display_error() con system()Arma un string con el nombre de archivo y lo pasa a una shell vía system()
Qube destino (gui-fatal.c)produce_message() con execlp()NoEjecuta zenity o kdialog directamente con execlp(), sin shell intermedia

sequenceDiagram
    participant Q as Qube comprometida
    participant D as Dom0
    Q->>D: confirmacion qfile con nombre de archivo malicioso
    D->>D: sanitize_remote_filename filtra solo no-ASCII y comillas dobles
    D->>D: display_error arma el dialogo con asprintf y system
    D-->>Q: la shell de dom0 ejecuta el comando inyectado
    Note over Q,D: la comilla simple rompe el contexto de comillas

Cómo protegerte y verificar el parche

La corrección está en el paquete qubes-core-dom0-linux, versión 4.3.22, para Qubes 4.3. Al momento del boletín el paquete estaba en el repositorio security-testing antes de migrar al repositorio estable.

# Actualizar dom0 incluyendo el repo de pruebas de seguridad
sudo qubes-dom0-update --enablerepo=security-testing

# Verificar la version instalada
rpm -q qubes-core-dom0-linux

Ese segundo comando debe devolver algo como qubes-core-dom0-linux-4.3.22-1.fc37 o superior. Si preferís la interfaz gráfica, la herramienta Qubes Update (accesible desde el menú de dom0) aplica el mismo paquete sin tocar la terminal.

Una vez que el paquete pase de security-testing al repositorio estable, alcanza con una actualización normal (sudo qubes-dom0-update, sin flags extra) para recibirlo.

Impacto y análisis

Esta falla es lo que suele llamarse un escalador de compromiso: por sí sola no le da a un atacante acceso a nada, porque exige que la qube de destino ya esté comprometida de antemano. El disparador es que el propio usuario, desde dom0, decida copiarle un archivo a esa qube con qvm-copy-to-vm.

Ese detalle importa para entender el diseño de Qubes OS: el modelo de aislamiento por compartimentos asume que las qubes individuales pueden estar comprometidas sin que eso afecte al resto del sistema, siempre que los canales entre dom0 y las qubes estén bien blindados. QSB-118 es exactamente el tipo de brecha que ese modelo busca eliminar: un canal legítimo (copiar un archivo) que termina filtrando control hacia dom0.

💭 Clave: en un sistema diseñado para que ninguna qube individual pueda tocar dom0, cualquier ruta de error que termine ejecutando código con privilegios de dom0 anula parte de esa garantía.

El boletín señala que todas las versiones de Qubes OS están afectadas, lo que confirma que el patrón de código (sanitize incompleto más system()) llevaba tiempo presente en la base de qvm-copy-to-vm.

Terminal mostrando la actualizacion de un paquete de seguridad en Linux
El fix llega como una actualización de paquete normal, sin pasos manuales adicionales. Foto de Ousa Chea en Unsplash

Qué sigue

Lo inmediato es la migración del paquete qubes-core-dom0-linux 4.3.22 desde security-testing hacia el repositorio estable, tras el período habitual de pruebas por parte de la comunidad. Para quienes administran instalaciones de Qubes OS en producción, vale la pena revisar si existen otros puntos del código que reutilicen el mismo patrón de asprintf() más system() para construir comandos con datos que vienen de una qube, ya que ese es exactamente el antipatrón que habilitó QSB-118.

El crédito del hallazgo es para el investigador identificado como Tim C., según el propio boletín, que no detalla si hubo un programa de recompensas asociado.

📖 Resumen en Telegram: Ver resumen

Probalo vos: corré sudo qubes-dom0-update --enablerepo=security-testing en tu dom0 y confirmá con rpm -q qubes-core-dom0-linux que ya tenés la versión 4.3.22.

Preguntas frecuentes

¿Qué es exactamente QSB-118?

Es el Qubes Security Bulletin 118, publicado el 28 de agosto de 2026, que describe una vulnerabilidad de ejecución de código arbitrario en dom0 a través del manejo de errores de qvm-copy-to-vm.

¿Necesito hacer algo además de actualizar dom0?

No. El boletín es explícito: basta con continuar actualizando con normalidad para recibir el paquete corregido; no hace falta ninguna acción manual adicional.

¿Por qué la copia del lado de la qube no es vulnerable pero la de dom0 sí?

Porque el manejador de errores de la qube usa execlp() para lanzar directamente zenity o kdialog, mientras que el de dom0 arma un string y lo ejecuta con system(), que sí pasa por una shell interpretable.

¿Cómo confirmo que mi Qubes OS ya tiene el parche?

Corriendo rpm -q qubes-core-dom0-linux en dom0: la versión instalada debe ser 4.3.22 o superior.

¿Esta vulnerabilidad requiere que ya haya un atacante en mi sistema?

Sí. Necesita que una qube ya esté comprometida y que el usuario ejecute qvm-copy-to-vm desde dom0 hacia esa qube específica; no es explotable de forma remota sin ese paso previo.

Referencias

📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.

Imagen destacada: Foto de Rohan en Unsplash


Andrés Morales

Desarrollador e investigador en inteligencia artificial. Escribe sobre modelos de lenguaje, frameworks, herramientas para devs y lanzamientos open source. Cubre papers de ML, ecosistema de startups tech y tendencias de programación.

0 Comentarios

Deja un comentario

Marcador de posición del avatar

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.