CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-28385

CVE-2026-28385: Server-Side Request Forgery in Canonical LXD Image Import

Amit Schendel
Amit Schendel
Senior Security Researcher

Nov 7, 2026·9 min read·7 visits

Executive Summary (TL;DR)

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.

Vulnerability Overview

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.

Root Cause Analysis

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:

  1. Destination IP Filtering: The dialer did not block connections to loopback addresses, RFC 1918 private address spaces, or RFC 3927 link-local subnets (169.254.0.0/16 and fe80::/10).
  2. DNS Pinning: Because hostname resolution occurred dynamically within the standard HTTP client lifecycle, an attacker could also utilize DNS rebinding techniques if simple string-based hostname validation had been present.
  3. Error Sanitization: When the outbound connection failed or returned non-image data, the daemon caught the low-level Go 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.

Code & Architectural Patch Analysis

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.

Exploitation Methodology

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.

Scenario 1: Localhost Service Discovery and Port Scanning

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:

  • Closed Port: Returns Get "http://127.0.0.1:6379": dial tcp 127.0.0.1:6379: connect: connection refused.
  • Filtered Port: The operation hangs until the HTTP client timeout expires, returning context deadline exceeded or i/o timeout.
  • Open Non-HTTP Port: Returns malformed HTTP response or EOF, confirming an active listener.
  • Open HTTP Port: Returns HTTP status errors (e.g., 404 Not Found, 401 Unauthorized) or archive unpacking errors (invalid tar header) if the HTTP server returned a 200 OK body.

Scenario 2: Cloud Metadata Probing and RFC 1918 Lateral Scanning

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.

Impact Assessment

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.

Remediation & Hardening

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=builtin

Finally, 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.

Official Patches

CanonicalGitHub Security Advisory GHSA-3gq2-x4qg-p4g6
CanonicalGitHub Pull Request #18462: LXD Security Hardening Guide Update
CanonicalOfficial LXD Documentation: Restrict Outbound Requests

Fix Analysis (3)

Technical Appendix

CVSS Score
5.0/ 10
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N
EPSS Probability
0.28%
Top 80% most exploited

Affected Systems

Canonical LXD (versions 4.12 through 6.9)

Affected Versions Detail

Product
Affected Versions
Fixed Version
LXD
Canonical
>= 4.12, <= 6.96.10
AttributeDetail
Vulnerability ClassCWE-918: Server-Side Request Forgery (SSRF)
CVSS v3.1 Score5.0 Medium (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N)
Attack VectorNetwork via REST API (POST /1.0/images)
Authentication RequiredYes (User with can_create_images entitlement)
EPSS Score0.28% (20.30th Percentile)
Affected VersionsCanonical LXD 4.12 through 6.9
Patched VersionCanonical LXD 6.10
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1005Data from Local System
Collection
T1580Cloud Infrastructure Discovery
Discovery
T1046Network Service Discovery
Discovery
CWE-918
Server-Side Request Forgery (SSRF)

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.

Vulnerability Timeline

Initial refactoring committed to replace unconstrained image downloads with centralized image registries (commit 08996fa031eebc2bc2f8e27148c2ba24386c01d0).
2026-04-14
Security hardening documentation updated in PR #18462 (commit 5976c92117b79d73437d7fab55e34cb80083edff) detailing outbound proxy filtering.
2026-06-16
CVE-2026-28385 and GitHub Security Advisory GHSA-3gq2-x4qg-p4g6 officially published by Canonical.
2026-06-26
Backward-compatible SimpleStreams allowlist committed (commits 4bbdb17ab67010446668e4b00a5175df5b6d55b4 and 886fcf5b7686bf59de78e239cec90a69e8fb9c65).
2026-09-01
Final switchover to image registries merged in PR #17680 (commit c4a919f3f4e21249d535d4030a33484313026111) for LXD 6.10.
2026-10-05
NVD published CVSS v3.1 analysis and CPE configurations.
2026-10-25

References & Sources

  • [1]CVE-2026-28385 Official CVE Record
  • [2]NVD Vulnerability Detail: CVE-2026-28385
  • [3]GitHub Security Advisory: GHSA-3gq2-x4qg-p4g6
  • [4]GitHub Pull Request #18462: Update Guide to Hardening Security for LXD
  • [5]GitHub Commit 5976c92: Hardening Guide Update
  • [6]GitHub Commit c4a919f: Image Registries Switchover
  • [7]GitHub Commit 4bbdb17: Transitional Image Source Allowlist
  • [8]Canonical LXD Security Hardening Documentation: Restrict Outbound Requests

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•40 minutes ago•CVE-2026-62361
5.5

CVE-2026-62361: Authenticated SQL Injection and Table Access Control Bypass in Listmonk Subscriber Export

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).

Alon Barad
Alon Barad
3 views•11 min read
•about 3 hours ago•GHSA-9J25-MM2H-2F76
9.9

CVE-2026-48750: Arbitrary File Write on Host via exec-output Symlink in Canonical LXD and Incus

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`.

Alon Barad
Alon Barad
6 views•12 min read
•about 4 hours ago•GHSA-VGHH-5RFX-XHQ8
9.9

CVE-2026-48749: Arbitrary Host File Read and Write via Malicious Image Symlink in Canonical LXD and Incus

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.

Amit Schendel
Amit Schendel
5 views•9 min read
•about 5 hours ago•GHSA-FMC8-P6Q7-75CC
9.9

GHSA-fmc8-p6q7-75cc: Argument Injection in Canonical LXD Backup Compression Leads to Host Root Code Execution

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.

Amit Schendel
Amit Schendel
6 views•10 min read
•about 6 hours ago•GHSA-PJFF-C2WC-F6JM
9.9

CVE-2026-48769: Arbitrary File Write and Remote Code Execution via Trusted Image Hash in Canonical LXD and Linux Containers Incus

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.

Alon Barad
Alon Barad
8 views•10 min read
•about 10 hours ago•CVE-2026-9639
6.5

CVE-2026-9639: Authenticated Denial of Service via Nil-Pointer Dereference in Canonical LXD Custom Volume Backup Import

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.

Amit Schendel
Amit Schendel
7 views•9 min read