GHSA-47w9-6r3f-938g: Authorization Bypass and Host Root Command Execution in Canonical LXD and Incus
Vulnerability ID: GHSA-47W9-6R3F-938G
CVSS Score: 9.9
Published: 2026-11-06
A missing authorization and configuration validation vulnerability in Canonical LXD and LXC Incus allows authenticated users within restricted projects to bypass project security boundaries. By smuggling prohibited low-level configuration directives (such as raw.lxc or raw.qemu) inside instance snapshots or backup archives, an attacker can restore these configurations within a restricted project and execute arbitrary commands with root privileges on the underlying host operating system.
TL;DR
Authenticated users in restricted LXD or Incus projects can bypass security restrictions by restoring instance snapshots or importing backups containing prohibited low-level hypervisor hooks (e.g., raw.lxc), leading to arbitrary command execution as root on the host OS.
⚠️ Exploit Status: POC
Technical Details
- Vulnerability ID: GHSA-47w9-6r3f-938g / CVE-2026-48751
- Weakness Class: CWE-862: Missing Authorization
- Attack Vector: Network (REST API)
- CVSS v3.1 Score: 9.9 Critical (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H)
- EPSS Score: 0.68% (52.67th Percentile)
- Security Impact: Container Escape / Host Root Command Execution
- Exploit Status: Public Proof-of-Concept Available
- CISA KEV Status: Not Listed
Affected Systems
- Canonical LXD
- LXC Incus
- LXD (LTS 4.0 / 5.0 series): >= 4.12.0, < 5.0.7 (Fixed in:
5.0.7) - LXD (LTS 5.21 series): >= 5.1.0, < 5.21.5 (Fixed in:
5.21.5) - LXD (Feature series): >= 6.0.0, < 6.9.0 (Fixed in:
6.9.0) - Incus: < 7.2.0 (Fixed in:
7.2.0)
Code Analysis
Commit: 5aac658
Validate instance snapshots against project restrictions when importing from backup in lxd/instances_post.go
diff --git a/lxd/instances_post.go b/lxd/instances_post.go --- a/lxd/instances_post.go +++ b/lxd/instances_post.go @@ -932,6 +902,56 @@ func createFromBackup(s *state.State, r *http.Request, projectName string, data + // Check restrictions/limits if defined on project. + if restrictions != nil { + err = limits.AllowInstanceCreation(s.GlobalConfig, *restrictions, req) + if err != nil { + return response.SmartError(err) + } + + for i, snapshot := range bInfo.Config.Snapshots { + if snapshot == nil { + return response.SmartError(fmt.Errorf("Nil instance snapshot definition found at index %d", i)) + } + + snapshotReq := api.InstancesPost{ + InstancePut: api.InstancePut{ + Architecture: snapshot.Architecture, + Config: snapshot.Config, + Devices: snapshot.Devices, + Ephemeral: snapshot.Ephemeral, + Profiles: snapshot.Profiles, + Stateful: snapshot.Stateful, + }, + Name: bInfo.Name + "/" + snapshot.Name, + Source: api.InstanceSource{}, + Type: api.InstanceType(bInfo.Config.Instance.Type), + } + + err = limits.AllowInstanceCreation(s.GlobalConfig, *restrictions, snapshotReq) + if err != nil { + return response.SmartError(err) + } + } + } Commit: a52e5d0
Validate snapshot config against project limits and restrictions during snapshot restore in lxd/instance_put.go (master)
diff --git a/lxd/instance_put.go b/lxd/instance_put.go --- a/lxd/instance_put.go +++ b/lxd/instance_put.go @@ -235,6 +235,32 @@ func instanceSnapRestore(s *state.State, projectName string, name string, snap s } } + // Build the instance config that restoring the snapshot would apply, so it can be + // validated against the project's restrictions and limits below. + snapProfileNames := make([]string, 0, len(source.Profiles())) + for _, profile := range source.Profiles() { + snapProfileNames = append(snapProfileNames, profile.Name) + } + + snapConfig := api.InstancePut{ + Config: source.LocalConfig(), + Devices: source.LocalDevices().CloneNative(), + Profiles: snapProfileNames, + } + + err = s.DB.Cluster.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.ClusterTx) error { + return limits.AllowInstanceUpdate(ctx, s.GlobalConfig, tx, projectName, name, snapConfig, inst.LocalConfig()) + }) + if err != nil { + return err + } + // Generate a new `volatile.uuid.generation` to differentiate this instance restored from a snapshot from the original instance. source.LocalConfig()["volatile.uuid.generation"] = uuid.New().String() Commit: 6b93b2a
Backport of snapshot restore project restriction validation to LXD 5.0 branch
Commit: cfd9f66
Backport of snapshot restore project restriction validation to LXD 5.21 branch
Exploit Details
- GitHub Security Advisory: Official advisory containing the proof-of-concept CLI commands to bypass project restrictions via snapshot restoration.
- GitHub Security Advisory (Incus): Upstream Incus security advisory detailing the reproduction steps using incus CLI.
Mitigation Strategies
- Upgrade Canonical LXD or LXC Incus to a patched version that enforces project restriction checks during snapshot restoration and backup ingestion.
- Audit all existing instances and snapshots in restricted projects for unauthorized low-level configuration keys such as raw.lxc and raw.qemu.
- Restrict untrusted users from migrating instances across projects or importing custom backup tarballs until patches are applied.
Remediation Steps:
- For Canonical LXD 5.0 LTS environments, upgrade the snap or package to version 5.0.7 or later.
- For Canonical LXD 5.21 LTS environments, upgrade the snap or package to version 5.21.5 or later.
- For Canonical LXD 6.x environments, upgrade to version 6.9.0 or later.
- For LXC Incus environments, upgrade the incus package to version 7.2.0 or later.
- Run an API audit across all restricted projects using 'lxc query /1.0/instances?recursion=2' (or 'incus query') to identify and delete any snapshots or active configurations containing prohibited raw.* directives.
References
- GitHub Advisory GHSA-47w9-6r3f-938g (Canonical LXD)
- GitHub Advisory GHSA-48q5-w887-33wv (LXC Incus)
- National Vulnerability Database (NVD) - CVE-2026-48751
- Official CVE.org Record - CVE-2026-48751
- Canonical LXD Fix Commit: Backup Snapshot Validation (5aac658c)
- Canonical LXD Fix Commit: Snapshot Restore Validation Master (a52e5d06)
- Canonical LXD Fix Commit: Snapshot Restore Validation 5.0 (6b93b2a0)
- Canonical LXD Fix Commit: Snapshot Restore Validation 5.21 (cfd9f66f)
- Canonical LXD Release 5.0.7
- Canonical LXD Release 5.21.5
Read the full report for GHSA-47W9-6R3F-938G on our website for more details including interactive diagrams and full exploit analysis.
