GHSA-7mr3-28h5-m5vx: Authorization Bypass and Cross-Project Volume Copy in Canonical LXD
Vulnerability ID: GHSA-7MR3-28H5-M5VX
CVSS Score: 7.7
Published: 2026-11-06
An authorization bypass vulnerability in Canonical LXD (tracked as GHSA-7mr3-28h5-m5vx and CVE-2026-55621, and as GHSA-64f3-v33m-w89f in Linux Containers Incus) allows an authenticated user with restricted project access to copy custom storage volumes and volume snapshots from unauthorized projects. The flaw resides in the storagePoolVolumesPost REST API handler, which verifies permissions on the destination project but fails to check whether the caller holds view entitlements on the source project or volume specified in the request body.
TL;DR
Authenticated users restricted to a single LXD project can bypass multi-tenant isolation and copy custom storage volumes from any other project by supplying an unauthorized source project name in a volume creation API request.
⚠️ Exploit Status: POC
Technical Details
- Vulnerability ID: GHSA-7mr3-28h5-m5vx / CVE-2026-55621
- Weakness Class: CWE-862 (Missing Authorization)
- CVSS v3.1 Score: 7.7 High (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N)
- Attack Vector: Network (HTTPS REST API on :8443)
- Affected Function: storagePoolVolumesPost (lxd/storage_volumes.go)
- Security Impact: Cross-project tenant isolation bypass and unauthorized storage volume duplication
- Exploit Maturity: Proof of Concept (PoC) Publicly Available
- Patched Versions: LXD 5.0.7, 5.21.5, 6.8
Affected Systems
- Canonical LXD
- Linux Containers Incus
- github.com/canonical/lxd
- Canonical LXD (5.0 LTS): < 5.0.7 (Fixed in:
5.0.7) - Canonical LXD (5.21 LTS): < 5.21.5 (Fixed in:
5.21.5) - Canonical LXD (6.x): < 6.8 (Fixed in:
6.8)
Code Analysis
Commit: 8a4ed50
lxd: check for can_view on source when copying volume
diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go index 95590688d06c..0a3b0b25fbd3 100644 --- a/lxd/storage_volumes.go +++ b/lxd/storage_volumes.go @@ -1067,6 +1067,34 @@ func storagePoolVolumesPost(d *Daemon, r *http.Request) response.Response { return response.BadRequest(fmt.Errorf("Currently not allowed to create storage volumes of type %q", req.Type)) } + if req.Source.Type == api.SourceTypeCopy { + if req.Source.Name == "" { + return response.BadRequest(errors.New("No source volume name supplied")) + } + + if req.Source.Project == "" { + req.Source.Project = requestProjectName + } + + sourceProjectName, err := project.StorageVolumeProject(s.DB.Cluster, req.Source.Project, cluster.StoragePoolVolumeTypeCustom) + if err != nil { + return response.SmartError(err) + } + + var sourceURL *api.URL + sourceVolumeName, snapshotName, isSnapshot := api.GetParentAndSnapshotName(req.Source.Name) + if isSnapshot { + sourceURL = entity.StorageVolumeSnapshotURL(sourceProjectName, req.Source.Location, req.Source.Pool, req.Type, sourceVolumeName, snapshotName) + } else { + sourceURL = entity.StorageVolumeURL(sourceProjectName, req.Source.Location, req.Source.Pool, req.Type, req.Source.Name) + } + + err = s.Authorizer.CheckPermission(r.Context(), sourceURL, auth.EntitlementCanView) + if err != nil { + return response.SmartError(err) + } + } + var poolID int64 var dbVolume *db.StorageVolume Commit: e2635a2
lxd: check for can_view on source when copying volume
Commit: eec1cf9
lxd: check for view permission on source project when copying volume
diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go index cdffd67a4f1f..12b33f1185f2 100644 --- a/lxd/storage_volumes.go +++ b/lxd/storage_volumes.go @@ -657,6 +657,21 @@ func storagePoolVolumesPost(d *Daemon, r *http.Request) response.Response { return response.BadRequest(fmt.Errorf("Currently not allowed to create storage volumes of type %q", req.Type)) } + if req.Source.Type == "copy" { + // Determine the effective source project for the permission check without mutating + // req.Source.Project. The cluster-internal copy path forwards req.Source.Project to the + // source member, where an empty value means "same as the request project". Setting it to an + // explicit value here would make that path treat the copy as a cross-project move and fail. + sourceProject := req.Source.Project + if sourceProject == "" { + sourceProject = requestProjectName + } + + if !s.Authorizer.UserHasPermission(r, sourceProject, "view") { + return response.Forbidden(nil) + } + } + poolID, err := s.DB.Cluster.GetStoragePoolID(poolName) if err != nil { return response.SmartError(err) Exploit Details
- GitHub Security Advisory: Official advisory containing reproduction steps and a Python proof-of-concept script demonstrating cross-project custom storage volume duplication.
Mitigation Strategies
- Upgrade Canonical LXD to patched versions (5.0.7, 5.21.5, or 6.8) that enforce 'view' / 'can_view' entitlement checks on the source project and volume during copy operations.
- Restrict network access to the LXD HTTPS REST API endpoint (TCP port 8443) to trusted management networks and administrative hosts.
- Audit trusted client certificates and remove unnecessary restricted certificates in multi-tenant environments until patches are applied.
- Monitor LXD API access logs and background operation events for cross-project custom storage volume copy requests.
Remediation Steps:
- Identify the currently installed LXD version and channel using 'snap list lxd' or 'lxd --version'.
- Refresh or upgrade the LXD package to at least 5.0.7 (for 5.0 LTS), 5.21.5 (for 5.21 LTS), or 6.8 (for 6.x feature branch).
- Verify that the daemon has restarted and is running the updated binary.
- Audit existing storage volumes across all restricted projects ('lxc storage volume list --all-projects') to ensure no unauthorized copies of sensitive volumes were created prior to patching.
References
- LXD Security Advisory (GHSA-7mr3-28h5-m5vx)
- Incus Security Advisory (GHSA-64f3-v33m-w89f)
- GitHub Advisory Database Entry (GHSA-7mr3-28h5-m5vx)
- Fix Commit (8a4ed50ae855639d76021ba4bf26a50d7f2288fd)
- Fix Commit (e2635a26957737ec4a77dc28dd7b84bd380881d6)
- Fix Commit LTS 5.0.x (eec1cf9504c18ad7c3c36ae0b62d21c05c25702c)
- National Vulnerability Database (CVE-2026-55621)
- Canonical LXD Upstream Repository
Read the full report for GHSA-7MR3-28H5-M5VX on our website for more details including interactive diagrams and full exploit analysis.


