GHSA-xhqx-mgh3-3h7q Incus: CreateCustomVolumeFromBackup nil-pointer dereference on volume_snapshots[*].expires_at (sibling-field variant of GHSA-r7w7)
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`:`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** |ReachAttacker 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.`POST /1.0/storage-pools/<pool>/volumes/custom` with `Content-Type: application/octet-stream` and `X-Incus-name: <name>`.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).`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`.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):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.Daemon panic from `/tmp/incus.out`: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 fixMirror the guard pattern already in use at lines 909-910 / 1134-1135 / 1422-1423:Reporter notesReported via Privately-Reported Vulnerability against `lxc/incus` by tonghuaroot.
CVSS v4.0 score: 2.1