Nov 7, 2026·9 min read·7 visits
Authenticated LXD users with image creation privileges can abuse the URL image import functionality to perform error-based port scanning and interact with internal HTTP services across loopback, private networks, and cloud metadata endpoints.
CVE-2026-28385 (GHSA-3gq2-x4qg-p4g6) is a Server-Side Request Forgery (SSRF) vulnerability in Canonical LXD versions 4.12 through 6.9. An authenticated user possessing the can_create_images entitlement can force the LXD daemon to execute arbitrary outbound HTTP and HTTPS requests via the /1.0/images API endpoint. Due to the absence of egress destination validation, an attacker can probe host loopback services, RFC 1918 private network segments, and cloud Instance Metadata Services (IMDS) from the network position of the privileged LXD daemon.
Canonical LXD is a system container and virtual machine manager built on top of Linux Containers (LXC) and QEMU. It exposes a REST API over a local UNIX domain socket and, optionally, over HTTPS on TCP port 8443. The daemon executes with root privileges on the host operating system and manages image caching, storage pools, network bridges, and instance lifecycles.
In Canonical LXD versions 4.12 through 6.9, the image import subsystem contains a Server-Side Request Forgery (CWE-918) vulnerability. When an authenticated user requests the creation or importation of a container or virtual machine image via the /1.0/images endpoint, the API allows the caller to specify an external URL or remote server as the image source.
Because the LXD daemon processes this URL directly using Go's standard HTTP client without validating the resolved destination IP address, the daemon can be directed to connect to restricted network destinations. Specifically, an attacker holding the can_create_images entitlement can force the LXD daemon to initiate TCP connections and send HTTP requests to the host loopback interface (127.0.0.0/8, ::1), internal RFC 1918 private networks (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), and link-local cloud Instance Metadata Services (169.254.169.254).
Although the target HTTP service does not return a valid LXD image archive, the daemon propagates synchronous and asynchronous network error states back to the API caller. By analyzing variations in these error messages and response timings, an authenticated attacker can map internal network topologies, determine port states, and interact with unauthenticated internal HTTP endpoints.
The root cause of CVE-2026-28385 is the combination of unrestricted user-supplied URL handling in the image download pipeline and verbose error propagation back to the unprivileged or project-scoped API client. LXD supports multiple image ingestion methods in lxd/images.go and lxd/daemon_images.go, including direct file uploads, remote LXD server pulls, SimpleStreams registries, and direct HTTP/HTTPS URL downloads.
When processing a POST /1.0/images request where source.type is set to url or image (in pull mode), the daemon extracts the target URL (source.url or source.server) directly from the JSON request body. In vulnerable versions between git commit 538ac3df036e4a8c0197d0f52d125be1b51879d0 and 3c94d4fae7ff57e0ee79850135a277f53a18753c, the ImageDownload routine passed this target directly into the underlying HTTP transport dialer without implementing a custom net.Dialer control function or pre-connection IP address verification.
Consequently, the network layer lacked three critical security controls:
169.254.0.0/16 and fe80::/10).net/http or net.OpError exceptions and included them directly in the operation metadata returned to the client.Because the LXD daemon typically runs directly on the host network namespace (rather than inside an isolated container network namespace), its outbound requests bypass perimeter firewalls and cloud security groups that restrict external traffic. It also shares the host's loopback interface and link-local routing table, granting it direct network adjacency to local administrative daemons and cloud metadata services.
Canonical remediated CVE-2026-28385 in LXD 6.10 through a fundamental architectural refactoring rather than relying solely on IP blocklists. In pull request #17680 (finalized in commit c4a919f3f4e21249d535d4030a33484313026111 and 3c94d4fae7ff57e0ee79850135a277f53a18753c), Canonical deprecated arbitrary client-supplied image URLs and remote server specifications in favor of administrator-controlled Image Registries (image_registries API extension).
In commit 08996fa031eebc2bc2f8e27148c2ba24386c01d0 (lxd/daemon_images: Update ImageDownload function to use image registries), the ImageDownload function was modified so that clients can no longer supply arbitrary URLs. Instead, image pulls must reference a pre-configured api.ImageRegistry object managed by the LXD administrator or tied to an authenticated cluster link (cluster_links) with pinned TLS certificate fingerprints (GetClusterLinkCertificateFingerprints).
To preserve backward compatibility for existing automation scripts that specify legacy source.server and source.protocol fields, Canonical introduced transitional resolution logic in commit 4bbdb17ab67010446668e4b00a5175df5b6d55b4 (lxd/image_source_transitional.go) and commit 886fcf5b7686bf59de78e239cec90a69e8fb9c65 (lxd/images.go). This transitional layer enforces a strict hostname allowlist for legacy SimpleStreams requests:
// lxd/image_source_transitional.go (Commit 4bbdb17ab67010446668e4b00a5175df5b6d55b4)
// Explicit allowlist for backward-compatible SimpleStreams image servers.
// Arbitrary URLs or IP addresses are rejected unless configured as a trusted registry.
var transitionalSimpleStreamsHosts = []string{
"cloud-images.ubuntu.com",
"images.lxd.canonical.com",
"cdimage.ubuntu.com",
}When a client submits a deprecated image source definition, the daemon verifies whether the requested hostname matches transitionalSimpleStreamsHosts or maps to an existing administrator-defined registry with verified certificate fingerprints. If the target URL points to an arbitrary IP address, localhost, or an unverified domain, the translation layer rejects the request before any outbound socket is opened.
> [!NOTE]
> Fix Completeness Assessment: Replacing arbitrary client-specified URLs with server-side Image Registries and strict hostname allowlisting completely eliminates the unvalidated URL vector in LXD 6.10+. For deployments remaining on older release branches or where administrators allow custom HTTP sources, Canonical also committed operational hardening guidance in commit 5976c92117b79d73437d7fab55e34cb80083edff (PR #18462), instructing operators to route all LXD outbound traffic through a restricted egress proxy via core.proxy_http and core.proxy_https.
Exploiting CVE-2026-28385 requires network connectivity to the LXD REST API (typically TCP port 8443) or access to the local UNIX socket, along with valid authentication credentials (a trusted client TLS certificate or OIDC token) granted the can_create_images entitlement within at least one LXD project.
An attacker can enumerate services bound strictly to the host's loopback interface (127.0.0.1), such as local Redis instances, Prometheus metrics endpoints, or internal control planes (e.g., Kubernetes kube-apiserver or etcd). The attacker sends a POST request to /1.0/images specifying a url source:
POST /1.0/images HTTP/1.1
Host: lxd-cluster.internal:8443
Content-Type: application/json
{
"source": {
"type": "url",
"url": "http://127.0.0.1:6379"
}
}Because image imports execute asynchronously in LXD, the API returns an operation UUID (/1.0/operations/<uuid>). The attacker queries the operation status endpoint to inspect the err field:
Get "http://127.0.0.1:6379": dial tcp 127.0.0.1:6379: connect: connection refused.context deadline exceeded or i/o timeout.malformed HTTP response or EOF, confirming an active listener.404 Not Found, 401 Unauthorized) or archive unpacking errors (invalid tar header) if the HTTP server returned a 200 OK body.Alternatively, an attacker can abuse the legacy simplestreams protocol handler or direct URL handler to probe cloud metadata endpoints (169.254.169.254) or internal management subnets:
POST /1.0/images HTTP/1.1
Host: lxd-cluster.internal:8443
Content-Type: application/json
{
"source": {
"type": "image",
"mode": "pull",
"server": "http://169.254.169.254/latest/meta-data/",
"protocol": "simplestreams",
"alias": "probe"
}
}When targeting internal HTTP endpoints across RFC 1918 ranges (such as http://10.0.0.15:8080/metrics), the LXD daemon performs a full HTTP GET request. While the raw response body is not directly echoed to the user if archive parsing fails, HTTP redirect targets, status codes, and specific parser errors allow the attacker to fingerprint internal web applications and trigger state-changing HTTP GET webhooks.
CVE-2026-28385 is rated 5.0 (Medium) under CVSS v3.1 with the vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N. The Scope: Changed (S:C) metric is critical to understanding the impact: while the vulnerable component is the LXD daemon, the impacted resources reside outside LXD's immediate security scope, encompassing the host operating system's loopback network, the surrounding local area network, and cloud provider metadata infrastructure.
In multi-tenant LXD deployments or enterprise environments utilizing Role-Based Access Control (RBAC), non-administrative developers are frequently granted restricted project access with the can_create_images entitlement so they can import custom base images. This vulnerability allows those restricted users to break out of their logical project isolation at the network layer and use the LXD host as a pivot point for internal reconnaissance.
The confidentiality impact (C:L) stems from the exposure of internal network topology, firewall rules, active port states, and HTTP service availability. Because LXD fails to unpack non-archive responses and discards the body, this is primarily a blind or semi-blind error-based SSRF rather than a full-read SSRF, which limits direct exfiltration of multi-line metadata credentials unless leaked via HTTP headers or error strings.
According to FIRST EPSS metrics, CVE-2026-28385 holds an EPSS score of 0.00278 (0.28%) at the 20.30th percentile, and it is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. The low probability of indiscriminate internet-wide exploitation is directly attributable to the prerequisite of valid authentication (PR:L) with TLS client certificates or enterprise identity tokens.
To fully remediate CVE-2026-28385, administrators should upgrade Canonical LXD to version 6.10 or later. LXD 6.10 replaces arbitrary image download URLs with centralized Image Registries and restricts legacy SimpleStreams requests to a hardcoded allowlist of official Canonical domains (cloud-images.ubuntu.com, images.lxd.canonical.com, and cdimage.ubuntu.com).
For environments that cannot immediately upgrade to LXD 6.10, or where defense-in-depth is required for outbound daemon traffic, operators should implement the official proxy hardening steps introduced in PR #18462. By configuring LXD to route all outbound HTTP and HTTPS requests through a dedicated egress filtering proxy (such as Squid or Smokescreen) that blocks connections to loopback, RFC 1918, and link-local IP ranges, SSRF attempts are neutralized at the proxy layer:
# Configure LXD to route outbound traffic through a hardening proxy
lxc config set core.proxy_http "http://egress-proxy.internal:3128"
lxc config set core.proxy_https "http://egress-proxy.internal:3128"Additionally, administrators should enforce strict RBAC and project-level restrictions. The can_create_images entitlement should be revoked from untrusted or standard user roles. On LXD 6.10+, non-administrative projects should be restricted to built-in registries:
# Restrict a project to only use built-in, administrator-approved image registries
lxc project set <project_name> restricted=true
lxc project set <project_name> restricted.registries=builtinFinally, ensure that the LXD API listener (core.https_address) is bound strictly to a dedicated management interface rather than wildcard interfaces (0.0.0.0:8443 or :8443), and implement host-level nftables or iptables rules matching the root / lxd daemon cgroup to reject outbound TCP connections toward 169.254.169.254/32 if cloud metadata access is not required by the daemon.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
LXD Canonical | >= 4.12, <= 6.9 | 6.10 |
| Attribute | Detail |
|---|---|
| Vulnerability Class | CWE-918: Server-Side Request Forgery (SSRF) |
| CVSS v3.1 Score | 5.0 Medium (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N) |
| Attack Vector | Network via REST API (POST /1.0/images) |
| Authentication Required | Yes (User with can_create_images entitlement) |
| EPSS Score | 0.28% (20.30th Percentile) |
| Affected Versions | Canonical LXD 4.12 through 6.9 |
| Patched Version | Canonical LXD 6.10 |
| CISA KEV Status | Not Listed |
The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.
CVE-2026-62361 (GHSA-xgjr-7j9q-2h4r) is an authenticated SQL injection and authorization bypass vulnerability in listmonk, an open-source, self-hosted newsletter and mailing list manager written in Go. In versions prior to 6.2.0, the subscriber export endpoint (GET /api/subscribers/export) directly interpolates user-supplied SQL filter expressions into a PostgreSQL query without invoking the table allowlist validation function (validateQueryTables). Consequently, authenticated users possessing the subscribers:sql_query and subscribers:get_all permissions can bypass relational access controls, execute arbitrary subqueries against restricted tables such as users and settings, and modify database state via writable Common Table Expressions (CTEs).
Canonical LXD and LXC Incus contain an arbitrary file write vulnerability (CWE-73 / CWE-59) in the `/1.0/instances/<name>/exec` REST API endpoint. When an instance is unpacked from an image archive, top-level symbolic links are extracted directly onto the host filesystem within the instance storage directory. If a crafted image includes a symbolic link named `exec-output` pointing to an arbitrary host path, invoking the execution endpoint with `record-output: true` causes the privileged host daemon to follow the symlink and write command output files directly to the target host directory. An authenticated attacker with permissions to import images and execute commands can exploit this flaw to write controlled content to sensitive host directories such as `/etc/cron.d`, resulting in arbitrary code execution on the host as `root`.
CVE-2026-48749 (tracked as GHSA-vghh-5rfx-xhq8 for LXD and GHSA-2q3f-q5pq-g8wv for Incus) is a critical container escape vulnerability in the Canonical LXD and Linux Containers Incus system container managers. By importing a specially crafted container image archive containing duplicate tar member headers, an authenticated attacker can replace the instance rootfs directory with a symbolic link pointing to the underlying host root filesystem. When performing file operations on a stopped container, the privileged forkfile helper binary resolves the symbolic link without confinement and chroots directly into the host filesystem, granting arbitrary root-level file read and write access.
GHSA-fmc8-p6q7-75cc (associated with CVE-2026-48755) is a critical argument injection vulnerability in Canonical LXD (github.com/canonical/lxd). The vulnerability occurs during instance and storage volume backup operations when processing the user-supplied compression_algorithm configuration parameter. While LXD validates the primary executable token against an allowlist of supported compression binaries, it fails to sanitize or restrict subsequent tokens parsed via shellquote.Split. These additional arguments are passed directly to exec.Command. An authenticated attacker with privileges to trigger backups can inject command-line flags for utilities like zstd to read staged files from a container filesystem and write them to arbitrary paths on the underlying host filesystem, such as /etc/cron.d/, achieving root-level arbitrary code execution on the host.
A critical path traversal vulnerability caused by improper input validation (CWE-20) exists in the direct image download handler of Canonical LXD and Linux Containers Incus. When an authenticated user requests an image import using the URL source type, the daemon reads the image fingerprint from an untrusted HTTP response header (`Incus-Image-Hash` or `LXD-Image-Hash`) without validating that it conforms to a SHA-256 format. This unvalidated string is concatenated directly into a filesystem path via `filepath.Join` prior to file creation and cryptographic verification, allowing directory traversal sequences to write arbitrary files on the host filesystem as root.
CVE-2026-9639 (GHSA-j93m-3j9p-m5m8) is a null pointer dereference vulnerability in Canonical LXD affecting versions 5.0.0 through 5.21.4 and 6.0 through 6.8. The flaw resides in the (*lxdBackend).CreateCustomVolumeFromBackup method within lxd/storage/backend_lxd.go. An authenticated attacker with the can_create_storage_volumes permission can upload a crafted custom volume backup tarball that omits the expires_at field on a snapshot entry, triggering an unhandled SIGSEGV panic and terminating the LXD daemon.