CVE-2026-9639
Authenticated Denial of Service via Malicious Backup Tarball in LXD
Nil-pointer dereference in CreateCustomVolumeFromBackup in LXD up to version 6.8 and 5.21 on Linux allows an authenticated user with can_create_storage_volumes permissions to cause a denial of service via a specially crafted custom-volume backup tarball that omits the expires_at snapshot field.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
6.5
Authenticated Denial of Service via Malicious Backup Tarball in LXD
Nil-pointer dereference in CreateCustomVolumeFromBackup in LXD up to version 6.8 and 5.21 on Linux allows an authenticated user with can_create_storage_volumes permissions to cause a denial of service via a specially crafted custom-volume backup tarball that omits the expires_at snapshot field.
- Record
CVE-2026-9639- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-476
- Updated
- 2026-11-02
EUVDEUVD-2026-39789
6.5
LXD has CreateCustomVolumeFromBackup nil-pointer dereference on volumes[0].snapshots[*].expires_at
- Record
EUVD-2026-39789- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-06
GitHub AdvisoriesGHSA-j93m-3j9p-m5m8
6.5
LXD has CreateCustomVolumeFromBackup nil-pointer dereference on volumes[0].snapshots[*].expires_at
Summary
(sibling-field variant of CVE-2026-40197 fix 05bc272)
(*lxdBackend).CreateCustomVolumeFromBackup in lxd/storage/backend_lxd.go contains an unguarded *time.Time dereference on the ExpiresAt field of every volume-snapshot entry in an imported custom-volume backup. An authenticated user with EntitlementCanCreateStorageVolumes permission on any project can crash the lxd daemon by uploading a backup tarball whose volumes[0].snapshots[*].expires_at field is omitted.
This is a sibling-field variant of the CVE-2026-40197 fix (commit 05bc272, "Validate snapshots from backup.yaml are non-nil", cherry-picked from incus commit 985a1dedf / GHSA-r7w7-mmxr-47r9). That fix added if snap == nil guards at several consumer sites, but did not guard the adjacent *snapshot.ExpiresAt deref at line 8216. Every other consumer of this field in the same file already gates the deref with if … != nil (e.g. lines 1010-1011, 1274-1275, 1856-1857, 2454-2455, 5070-5071, 5527-5528). Asymmetric guard is the bug.
Vulnerable code
lxd/storage/backend_lxd.go, CreateCustomVolumeFromBackup:
// Line 8141-8150 — earliest snapshot validation pass (caches s == nil)
for i, snap := range customVol.Snapshots {
if snap == nil {
return fmt.Errorf("Nil custom volume snapshot definition found at index %d", i)
}
err = drivers.ValidVolumeName(snap.Name)
...
}
// Line 8196-8216 — the snapshot DB-create loop
for i, s := range customVol.Snapshots {
if s == nil {
return fmt.Errorf("Nil custom volume snapshot definition found at index %d", i)
}
snapshot := s
...
// Line 8216 — UNGUARDED *time.Time deref:
err = VolumeDBCreate(b, srcBackup.Project, fullSnapName, snapshot.Description,
snapVol.Type(), true, snapVol.Config(), snapshot.CreatedAt,
*snapshot.ExpiresAt, // <-- panics when expires_at omitted in YAML
snapVol.ContentType(), true, true)
ExpiresAt is declared *time.Time (shared/api/storage_pool_volume_snapshot.go). Every other consumer in the same file already uses the safe pattern (if … != nil { … = *… }):
| Line | Code | Guarded? | |------|------|----------| | 1010-1011 | rootVol.Snapshots[i].ExpiresAt | YES | | 1274-1275 | rootVol.Snapshots[i].ExpiresAt | YES | | 1558-1559 | srcSnap.ExpiresAt | YES | | 1856-1857 | rootVol.Snapshots[i].ExpiresAt | YES | | 2454-2455 | rootVol.Snapshots[i].ExpiresAt | YES | | 5070-5071 | customVol.Snapshots[i].ExpiresAt | YES | | 5527-5528 | srcSnap.ExpiresAt | YES | | 8216 | CreateCustomVolumeFromBackup snapshot.ExpiresAt | NO |
Reach
- Attacker is an authenticated client (TLS cert, OIDC, or unix socket) with the
EntitlementCanCreateStorageVolumesentitlement on any project. Same auth gate as CVE-2026-40197. POST /1.0/storage-pools/<pool>/volumes/customwithContent-Type: application/octet-streamandX-LXD-name: <name>.- Body is a tar containing
backup/index.yamlwithtype: custom,volumes[0]non-nil, andvolumes[0].snapshots[0]non-nil but missingexpires_at. lxd/storage_volumes.go:storagePoolVolumesPost->backup.GetInfoparses the yaml ->pool.CreateCustomVolumeFromBackup-> the validations at 8141-8150 + 8197 pass (snapshot pointer is non-nil, name is valid) ->*snapshot.ExpiresAton line 8216 panics on the nil*time.Time.- The Go runtime kills the entire
lxddaemon process. Repeated POSTs are a persistent denial of service.
Minimal backup/index.yaml:
name: poc-vol
backend: dir
pool: default
type: custom
optimized: false…
- Record
GHSA-j93m-3j9p-m5m8- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-476
- Updated
- 2026-11-06
NVD
6.5
Nil-pointer dereference in CreateCustomVolumeFromBackup in LXD up to version 6.8 and 5.21 on Linux allows an authenticated user with can_create_storage_volumes permissions to cause a denial of service via a specially crafted custom-volume backup tarball that omits the expires_at snapshot field.
- Record
CVE-2026-9639- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-476
- Updated
- 2026-11-02
OSV
6.5
Authenticated Denial of Service via Malicious Backup Tarball in LXD
Nil-pointer dereference in CreateCustomVolumeFromBackup in LXD up to version 6.8 and 5.21 on Linux allows an authenticated user with can_create_storage_volumes permissions to cause a denial of service via a specially crafted custom-volume backup tarball that omits the expires_at snapshot field.
- Record
CVE-2026-9639- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-476
- Updated
- 2026-11-02
OSVDEBIAN-CVE-2026-9639
6.5
Nil-pointer dereference in CreateCustomVolumeFromBackup in LXD up to version 6.8 and 5.21 on Linux allows an authenticated user with can_create_storage_volumes permissions to cause a denial of service via a specially crafted custom-volume backup tarball that omits the expires_at snapshot field.
- Record
DEBIAN-CVE-2026-9639- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
OSVGHSA-j93m-3j9p-m5m8
6.5
LXD has CreateCustomVolumeFromBackup nil-pointer dereference on volumes[0].snapshots[*].expires_at
Summary
(sibling-field variant of CVE-2026-40197 fix 05bc272)
(*lxdBackend).CreateCustomVolumeFromBackup in lxd/storage/backend_lxd.go contains an unguarded *time.Time dereference on the ExpiresAt field of every volume-snapshot entry in an imported custom-volume backup. An authenticated user with EntitlementCanCreateStorageVolumes permission on any project can crash the lxd daemon by uploading a backup tarball whose volumes[0].snapshots[*].expires_at field is omitted.
This is a sibling-field variant of the CVE-2026-40197 fix (commit 05bc272, "Validate snapshots from backup.yaml are non-nil", cherry-picked from incus commit 985a1dedf / GHSA-r7w7-mmxr-47r9). That fix added if snap == nil guards at several consumer sites, but did not guard the adjacent *snapshot.ExpiresAt deref at line 8216. Every other consumer of this field in the same file already gates the deref with if … != nil (e.g. lines 1010-1011, 1274-1275, 1856-1857, 2454-2455, 5070-5071, 5527-5528). Asymmetric guard is the bug.
Vulnerable code
lxd/storage/backend_lxd.go, CreateCustomVolumeFromBackup:
// Line 8141-8150 — earliest snapshot validation pass (caches s == nil)
for i, snap := range customVol.Snapshots {
if snap == nil {
return fmt.Errorf("Nil custom volume snapshot definition found at index %d", i)
}
err = drivers.ValidVolumeName(snap.Name)
...
}
// Line 8196-8216 — the snapshot DB-create loop
for i, s := range customVol.Snapshots {
if s == nil {
return fmt.Errorf("Nil custom volume snapshot definition found at index %d", i)
}
snapshot := s
...
// Line 8216 — UNGUARDED *time.Time deref:
err = VolumeDBCreate(b, srcBackup.Project, fullSnapName, snapshot.Description,
snapVol.Type(), true, snapVol.Config(), snapshot.CreatedAt,
*snapshot.ExpiresAt, // <-- panics when expires_at omitted in YAML
snapVol.ContentType(), true, true)
ExpiresAt is declared *time.Time (shared/api/storage_pool_volume_snapshot.go). Every other consumer in the same file already uses the safe pattern (if … != nil { … = *… }):
| Line | Code | Guarded? | |------|------|----------| | 1010-1011 | rootVol.Snapshots[i].ExpiresAt | YES | | 1274-1275 | rootVol.Snapshots[i].ExpiresAt | YES | | 1558-1559 | srcSnap.ExpiresAt | YES | | 1856-1857 | rootVol.Snapshots[i].ExpiresAt | YES | | 2454-2455 | rootVol.Snapshots[i].ExpiresAt | YES | | 5070-5071 | customVol.Snapshots[i].ExpiresAt | YES | | 5527-5528 | srcSnap.ExpiresAt | YES | | 8216 | CreateCustomVolumeFromBackup snapshot.ExpiresAt | NO |
Reach
- Attacker is an authenticated client (TLS cert, OIDC, or unix socket) with the
EntitlementCanCreateStorageVolumesentitlement on any project. Same auth gate as CVE-2026-40197. POST /1.0/storage-pools/<pool>/volumes/customwithContent-Type: application/octet-streamandX-LXD-name: <name>.- Body is a tar containing
backup/index.yamlwithtype: custom,volumes[0]non-nil, andvolumes[0].snapshots[0]non-nil but missingexpires_at. lxd/storage_volumes.go:storagePoolVolumesPost->backup.GetInfoparses the yaml ->pool.CreateCustomVolumeFromBackup-> the validations at 8141-8150 + 8197 pass (snapshot pointer is non-nil, name is valid) ->*snapshot.ExpiresAton line 8216 panics on the nil*time.Time.- The Go runtime kills the entire
lxddaemon process. Repeated POSTs are a persistent denial of service.
Minimal backup/index.yaml:
name: poc-vol
backend: dir
pool: default
type: custom
optimized: false…
- Record
GHSA-j93m-3j9p-m5m8- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-476
- Updated
- 2026-11-06
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
github.com/canonical/lxdGo |
before 0.0.0-20260622081844-85f897013ccd | 0.0.0-20260622081844-85f897013ccd |
lxdDebian:12 |
All versions, plus listed versions 5.0.2+git20231211.1364ae4-15.0.2+git20231211.1364ae4-25.0.2+git20231211.1364ae4-35.0.2+git20231211.1364ae4-45.0.2+git20231211.1364ae4-5 Show 12 moreShow less5.0.2+git20231211.1364ae4-65.0.2+git20231211.1364ae4-75.0.2+git20231211.1364ae4-85.0.2+git20231211.1364ae4-95.0.2-55.0.2-5+deb12u15.0.2-5+deb12u25.0.2-5+deb12u35.0.2-5+deb12u45.0.2-5+deb12u55.0.2-5+deb12u65.0.2-6 |
None known |
lxdDebian:13 |
before 5.0.2+git20231211.1364ae4-9+deb13u7, plus listed versions 5.0.2+git20231211.1364ae4-95.0.2+git20231211.1364ae4-9+deb13u15.0.2+git20231211.1364ae4-9+deb13u25.0.2+git20231211.1364ae4-9+deb13u35.0.2+git20231211.1364ae4-9+deb13u45.0.2+git20231211.1364ae4-9+deb13u55.0.2+git20231211.1364ae4-9+deb13u6 |
5.0.2+git20231211.1364ae4-9+deb13u7 |
History
| Recorded | Changed | Sources |
|---|---|---|
| published | EUVD | |
| affected, references | OSV | |
| affected, facts, references | GitHub Advisories | |
| first indexed | CVE List, EUVD, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-9639 is a medium vulnerability (CVSS 6.5) in Canonical Lxd, published June 26, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.55%, the 46th percentile. Fixed in github.com/canonical/lxd 0.0.0-20260622081844-85f897013ccd.
References
github.com/canonical/lxd/security/advisories/GHSA-j93m-3j9p-m5m8
github.com/canonical/lxd/pull/18320
github.com/canonical/lxd/pull/18390
nvd.nist.gov/vuln/detail/CVE-2026-9639
github.com/canonical/lxd/commit/05bc2729e99707a766d5c4705167a3322c9ef424
github.com/canonical/lxd/commit/c7cdfadb6044dfeaac592dc225978b4125ee23fe
Show 9 moreShow less
github.com/canonical/lxd/commit/d15520809e6e2ac2af0c6354dfb7be5854b0e859
github.com/CVEProject/cvelistV5/blob/main/cves/2026/9xxx/CVE-2026-9639.json
github.com/canonical/lxd/blob/lxd-5.0.7/lxd/storage/backend_lxd.go
github.com/canonical/lxd/releases/tag/lxd-5.21.5
github.com/canonical/lxd/releases/tag/lxd-6.9
github.com/advisories/GHSA-j93m-3j9p-m5m8
github.com/CVEProject/cvelistV5/tree/main/cves/2026/9xxx/CVE-2026-9639.json
github.com/canonical/lxd
security-tracker.debian.org/tracker/CVE-2026-9639
Left out here: the rest of 2 source descriptions. The JSON record has them.