NEWS

Qubes OS fixes critical flaw that allows code execution in dom0 via qvm-copy-to-vm

QSB-118 describes how a compromised qube can inject arbitrary commands into the privileged domain during the error report of a file copy. All versions of Qubes OS are affected.

Qubes OS fixes critical flaw that allows code execution in dom0 via qvm-copy-to-vm
Image: Redação iMasters

QSB-118 describes how a compromised qube can inject arbitrary commands into the privileged domain during the error report of a file copy. All versions of Qubes OS are affected.

The Qubes OS team published, on August 29, 2026, the Qubes Security Bulletin 118 (QSB-118), which describes an arbitrary code execution vulnerability in dom0, the system's privileged administrative domain. According to the bulletin, the flaw lies in the error-reporting path of the qvm-copy-to-vm tool when a file is copied from dom0 to a qube. All versions of Qubes OS are affected.

For those who use Qubes as an isolated workstation (journalists, security researchers, lawyers, people who handle sensitive data), dom0 is precisely the piece that should never be compromised: all control of the virtual machines originates from it. Code execution there means, in the bulletin's own words, that the attacker "can take over the Qubes OS system".

What needs to happen for the flaw to be exploited

The vulnerability is not remotely triggerable out of nowhere. The bulletin is explicit about the chain of preconditions:

  • A qube must already be compromised by the attacker.
  • The user needs to initiate, from dom0, a qvm-copy-to-vm call copying a file to that compromised qube.

If these two conditions combine, the malicious qube can inject an arbitrary command into dom0. In other words: this is an escalation scenario starting from a qube already under the adversary's control, not a first-access attack. Still, the impact is the worst possible, because it breaks exactly the isolation boundary that justifies using Qubes.

Where the bug lies: incomplete sanitization and system()

qvm-copy-to-vm uses the "qfile" protocol, a simplified file format that includes, at the end of the transfer, an acknowledgment sent by the destination back to the origin. This acknowledgment carries a checksum, an error code, and the name of the last file received, all controllable by the destination qube. In case of error, dom0 displays a graphical dialog with this information, including the file name reported by the qube.

The problem lies in how this name is handled. The sanitize_remote_filename() function iterates over the string and replaces with _ only characters outside the printable ASCII range and double quotes:

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

As the bulletin itself summarizes, this sanitization lets shell metacharacters through. The name, still tainted, reaches the error function display_error(), which builds the dialog command (kdialog or zenity) and executes it via system():

c
ret = stat("/usr/bin/kdialog", &st_buf);
if (asprintf(&dialog_cmd, "%s '%s: %s (error type: %s)'", ...) < 0) {
    ...
}
system(dialog_cmd);

Because system() passes the string through the shell, the file name chosen by the attacker is interpreted as a command. It's a classic command injection, made worse by running in the system's most privileged context.

The bulletin notes that the VM-side variant is not affected, because its error-reporting function doesn't use system(): it calls fork() and then execlp() directly with separate arguments, without going through the shell.

How to fix it

The package with the fix is qubes-core-dom0-linux version 4.3.22, for Qubes 4.3, in dom0. The bulletin states that no special action is needed beyond updating normally: the package migrates from the security-testing repository to stable after a short period of community testing, and should be installed via the Qubes update tool or its command-line equivalents.

| Item | Detail | |---|---| | Bulletin | QSB-118 | | Affected systems | All versions of Qubes OS | | Fixed package | qubes-core-dom0-linux 4.3.22 (Qubes 4.3, dom0) | | User action | Update normally | | Discovered by | Tim C. |

As is standard practice for the project, the QSB comes accompanied by PGP signatures from Marek Marczykowski-Górecki and Simon Gaiser (HW42). The team stresses that the only way to guarantee a bulletin is authentic is to verify these signatures against the Qubes Master Signing Key, a procedure detailed on the announcement page itself, which makes sense for anyone who trusts dom0 as the root of their own security.

The community's take

In the Hacker News thread, charcircuit points out the original sin of the code pattern:

"Another example for why system() is so dangerous to use. I also don't understand why it needs to show the dialog in dom0. If you have the option to handle attacker controlled input on the unprivileged side, you should do that instead of putting a lot of logic on the privileged side."

>

-- charcircuit

The criticism echoes the very structure of the flaw: placing processing of attacker-controlled input on the privileged side is the kind of decision that turns a string bug into full compromise.

Meanwhile, polotics downplays the practical risk for the average user, noting that "I would not have copied anything from dom0 to any another qube, the impact is low", precisely because copying files from dom0 is an uncommon day-to-day operation. It's a useful reminder: the trigger depends on a habit that most well-guided users avoid.

What remains open

The bulletin does not mention a CVE identifier nor indicate that the flaw has been exploited in the field, only crediting the discovery to Tim C. For the Brazilian professional running Qubes on a sensitive work machine, the message is direct: apply the dom0 update as soon as qubes-core-dom0-linux 4.3.22 reaches the stable repository, and in the meantime, treat qvm-copy-to-vm operations from dom0 as a move to avoid, especially for qubes of doubtful trust.

Translated from the Brazilian Portuguese original · Read the original