Introduction
A missing pair of entries in a hardcoded denylist is all it takes to turn a restricted LXD virtual machine user into a full host root administrator. CVE-2026-34177, scored at CVSS 9.1, is a privilege escalation path in Canonical LXD. It chains an AppArmor rule injection with a QEMU configuration injection to bridge the LXD control socket directly into a guest VM.
LXD is Canonical's system container and virtual machine manager. It provides a unified REST API for managing full Linux system images across bare metal and cloud infrastructure. It is widely deployed in multi-tenant environments, CI/CD pipelines, and development platforms where project-level restrictions are the primary isolation boundary. Canonical took direct stewardship of LXD from the Linux Containers community in July 2023, at version 5.15, and ships it as a default snap on Ubuntu Server installations.
Technical Information
Root Cause: Incomplete Denylist in VM Restriction Enforcement
The vulnerability lives in the isVMLowLevelOptionForbidden function within lxd/project/limits/permissions.go. When a project sets restricted.virtual-machines.lowlevel=block, LXD consults this function to decide whether to reject a given configuration key. The function holds a hardcoded list of forbidden keys, but the list omits two keys that are critical to VM confinement:
raw.apparmor: Lets a user inject arbitrary AppArmor rules into the confinement profile applied to the QEMU process.raw.qemu.conf: Lets a user inject arbitrary sections into the QEMU machine configuration file.
The flaw is classified under CWE-184: Incomplete List of Disallowed Inputs.
The equivalent function for containers, isContainerLowLevelOptionForbidden, already lists raw.apparmor as forbidden. The VM function never received the same treatment, and the parity lapse went unnoticed across multiple release cycles, from version 4.12 through 6.7.
The patched version of the function adds both missing keys:
func isVMLowLevelOptionForbidden ( key string ) bool { return slices. Contains ( string { "boot.host_shutdown_timeout", "limits.memory.hugepages", "raw.apparmor", "raw.idmap", "raw.qemu", "raw.qemu.conf", }, key ) }
Attack Flow
An attacker needs can_edit permissions on a virtual machine instance within a restricted project, which is a legitimate permission level in multi-tenant LXD deployments. The exploitation chain has five stages:
Stage 1: AppArmor Rule Injection. The attacker sets the raw.apparmor configuration key on their VM. The injected rule grants the QEMU process read and write access to the LXD Unix socket at /var/snap/lxd/common/lxd/unix.socket. Because the denylist does not block raw.apparmor, the LXD API accepts this configuration without complaint.
Stage 2: QEMU Configuration Injection. The attacker sets the raw.qemu.conf configuration key to add two elements to the QEMU machine definition: a chardev section that points to the LXD Unix socket, and a device section that creates a virtserialport connected to that chardev. Again, the denylist does not block this key.
Stage 3: Socket Bridging on VM Startup. When the virtual machine starts (or restarts), QEMU opens a connection to the LXD Unix socket on the host and exposes it inside the guest as /dev/virtio-ports/lxd.exploit. The guest VM now has a direct, authenticated communication channel to the LXD daemon on the host.
Stage 4: Privilege Escalation to Cluster Administrator. From inside the guest, the attacker sends a single HTTP request through the bridged socket to add the admin entitlement to their own group. The LXD daemon treats the request as if it came from a local, trusted client, because the connection arrives over the Unix socket.
Stage 5: Host Root Access. With cluster administrator privileges, the attacker creates a privileged container, mounts the host root filesystem into it, and obtains full host root access.
CVSS Metrics
The CVSS v3.1 vector reflects the severity of this chain:
| Metric | Value | Operational Implication |
|---|---|---|
| Attack Vector | Network | Exploitable remotely via the LXD API |
| Attack Complexity | Low | The exploit is trivial and requires no misconfiguration |
| Privileges Required | High | Requires can_edit permissions on a virtual machine |
| User Interaction | None | No interaction from other users is needed |
| Scope | Changed | The attack escapes the virtual machine to compromise the host |
| Confidentiality | High | Full access to host data |
| Integrity | High | Full ability to modify host systems |
| Availability | High | Full ability to disrupt host operations |
The "Changed" scope is the main driver of the 9.1 score. The vulnerability does not stay inside the VM boundary. It crosses from guest to host and from restricted user to root.
Affected Systems and Versions
The vulnerability affects Canonical LXD versions 4.12 through 6.7. Any deployment that relies on the restricted.virtual-machines.lowlevel=block project restriction for multi-tenant isolation is vulnerable.
Canonical has released patched versions across all supported series:
| LXD Series | Interim Snap Release | Final Patched Version |
|---|---|---|
| Series 6 | 6.7 d814d89 | 6.8 |
| Series 5.21 LTS | 5.21.4 aee7e08 | 5.21.5 |
| Series 5.0 LTS | 5.0.6 7fc3b36 | 5.0.7 |
| Series 4.0 LTS | 4.0.10 e92d947 | Not specified in advisory |
Deployments that do not use restricted projects, or that do not grant can_edit permissions on VM instances to untrusted users, have reduced exposure but should still patch.
Vendor Security History
Canonical handled this disclosure responsibly. It coordinated and released interim snap fixes across four supported branches between March 27 and March 30, 2026, well ahead of the public advisory on April 9, 2026. The same update cycle also bundled fixes for other critical vulnerabilities, including a TLS certificate privilege escalation and a backup import restriction bypass. That suggests Canonical conducted a broader security audit of the LXD project restrictions subsystem in response to this report.
A researcher identified as mpurg disclosed the vulnerability responsibly.
References
- GitHub Security Advisory: GHSA-fm2x-c5qw-4h6f
- Pull Request #17909: Prevent use of raw.apparmor and raw.qemu.conf when low level options are blocked
- CWE-184: Incomplete List of Disallowed Inputs
- LXD 6.7 Interim Snap Release 6.7-d814d89
- LXD 5.21.4 LTS Interim Snap Release 5.21.4-aee7e08
- LXD 5.0.6 LTS Interim Snap Release 5.0.6-7fc3b36
- LXD 4.0.10 LTS Interim Snap Release 4.0.10-e92d947
- LXD Documentation



