Like a bouncer checking only a photocopy of an ID against the club's logo, LXD's HTTPS listener accepts any forged trusted-client certificate chain
CVE-2026-112816 is an improper certificate validation flaw in Canonical LXD's HTTPS listener. Affected versions are 4.0.14, 5.0.10, 5.21.8, and 6.9; fixed in 4.0.15, 5.0.11, 5.21.9, and 6.10.1. An unauthenticated attacker who can reach the LXD API over TLS can present a crafted certificate chain and authenticate as any already-trusted client, gaining full API access to the cluster and managed virtual machines.
Canonical has not published a vendor CVSS score for this record, so there is no vendor baseline to compare against. That absence understates the problem: LXD is a hypervisor/container-host control plane, not a low-value utility. Once the HTTPS listener is enabled and reachable, this is an unauthenticated remote API takeover with cluster-wide and VM-level consequences. We assess it as CRITICAL. The assessment relies on the supplied official CVE record description; no independent live web source was verifiable at analysis time.
5 steps from start to impact.
Reach an exposed LXD HTTPS listener
core.https_address. An attacker probes the network for LXD certificate endpoints or identifies a host via internal service discovery. Default LXD uses a local Unix socket, but cluster members and remote dashboard/CLI access often bind to an interface.- Network route to the LXD API
core.https_addressorcluster.https_addressset to a reachable interface- TLS port not blocked by host firewall or NGFW
- Default configuration listens only on a Unix socket
- Most enterprise LXD clusters expose the API only on a dedicated management VLAN
- Firewall/NSG rules often restrict 8443 to admin jump hosts
Forge a trusted-client certificate chain
- Vulnerable LXD version
- Attacker can supply an arbitrary certificate chain during TLS client authentication
- No external TLS-terminating proxy that performs strict client CA validation before LXD
- Requires the attacker to craft a specific chain exploiting the validation logic
- Fixed in patched versions
- A TLS-terminating proxy with strict client CA validation may block the chain before it reaches LXD
Authenticate to LXD API as an arbitrary trusted client
- Listener runs vulnerable certificate-validation code
- Trust policy grants the impersonated client admin rights, typical for remote admin certificates
- If the LXD trust store uses per-client granular RBAC, the impersonated identity may be limited
- Patched versions reject the malformed chain
Enumerate and control the cluster and managed workloads
- Authenticated API session
- LXD daemon runs with sufficient privilege to create/modify profiles, default for admin
- Strict RBAC or immutable profiles may limit the attacker to a subset of workloads
- Host-level EDR or kernel hardening may alert on new privileged containers
- Cluster network segmentation may contain initial node compromise
lxc exec and host filesystem mounts.Compromise LXD hosts and adjacent systems
/mnt/host — or with security.privileged=true, the attacker can write to host init scripts, add SSH keys, or exploit kernel-mediated escapes to gain host root. Compromise of a cluster member can then propagate using existing LXD trust relationships and shared storage.- Privileged container or profile creation permitted
- Host filesystem mounts allowed by LXD config
- No AppArmor/SELinux policy blocking host path access
- LXD defaults to unprivileged containers and AppArmor confinement
- Some profiles disable host disk mounts or privileged mode
- Storage/network segmentation may slow lateral movement
/etc and /root from a container.core.https_address/cluster.https_address or bind to 127.0.0.1; use Unix socket over SSH for management. Deploy within 3 days (noisgate mitigation SLA for CRITICAL). This removes the vulnerable listener from the network path.lxc profile create, lxc config device add, and lxc exec events.- Client-side AppArmor profiles on containers do not stop the initial certificate authentication or API takeover; they only limit later container escape.
- A WAF or typical HTTP inspection cannot evaluate raw TLS client certificate chain validation flaws unless it terminates mTLS with strict independent trust.
- Restricting the LXD API to the same server VLAN but allowing all servers does not meaningfully reduce risk in a flat data-center network; an attacker with a foothold on one host can still reach the API.
The supporting signals.
| In-the-wild status | No public exploitation, CISA KEV not listed; no GreyNoise or Shodan IOCs located at assessment time. |
|---|---|
| PoC availability | No public GitHub repo or PocIndex entry for CVE-2026-112816 located; exploitation likely requires a custom crafted chain. |
| EPSS | Not published for this CVE. |
| KEV | Not listed. |
| CVSS vector (assessed) | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H — scope changed because host cluster/VMs are impacted. |
| Affected versions | 4.0.14, 5.0.10, 5.21.8, 6.9; fixed in 4.0.15, 5.0.11, 5.21.9, 6.10.1 |
| Exposure | Default LXD binds to a Unix socket; remote API exposure is uncommon publicly but relevant on management VLANs and backup/cluster networks. |
| Disclosure date | 2026-10-30 |
| Reporting researcher/org | Not provided in the official record supplied. |
| CWE | CWE-295 Improper Certificate Validation |
Sources.
Why this verdict
- Assessed baseline: No vendor CVSS exists; starting from vulnerability properties (unauthenticated remote, low complexity, high CIA impact) aligns with CVSS 9.3–9.8.
- Role multiplier: LXD is a hypervisor/container control plane. On management VLANs and cluster nodes, full API takeover is fleet- and VM-scale; compromise can reach host root via privileged container profiles. This floors the verdict at CRITICAL under noisgate high-value-role rules.
- Friction audit: The biggest real-world narrowing is exposure — default LXD does not listen on TCP, and most enterprises bind the API to a management VLAN. That does not break the CRITICAL floor for a hypervisor/container-host role, but it prevents a score of 10.
Why not higher?
Not a 10.0 because the attack requires a reachable HTTPS listener rather than default Unix-socket-only access. Most installations do not expose the API to the public internet, and no active exploitation or public PoC has been observed. A 9.3 reflects an unauthenticated chain-to-cluster takeover on exposed systems with meaningful but not universal reach.
Why not lower?
Cannot be below CRITICAL because the vulnerable component is canonically a high-value hypervisor/container-host role. Successful exploitation yields cluster-wide and VM-level control, with plausible host root via privileged containers. Network reachability alone does not lower the floor under noisgate rules when the affected role is hypervisor-scale.
Crowdsourced verification payload.
Run on each LXD node as root (or via sudo) from a management shell. Example: sudo bash check_cve_2026_112816_lxd.sh. The script checks the installed LXD version via lxd --version or snap, compares against patched lines, and exits 0 for PATCHED, 1 for VULNERABLE, 2 for UNKNOWN.
#!/usr/bin/env bash
# CVE-2026-112816 LXD version check
# Exit 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
ver_ge() {
awk -v a="$1" -v b="$2" 'BEGIN{ split(a,av,"."); split(b,bv,"."); for(i=1;i<=3;i++){ av[i]=av[i]+0; bv[i]=bv[i]+0; } if(av[1]>bv[1] || (av[1]==bv[1] && av[2]>bv[2]) || (av[1]==bv[1] && av[2]==bv[2] && av[3]>=bv[3])){ exit 0 } else { exit 1 } }'
return $?
}
VRAW=""
if command -v lxd >/dev/null 2>&1; then
VRAW=$(lxd --version 2>/dev/null | awk '{print $1}')
fi
if [ -z "$VRAW" ] && command -v snap >/dev/null 2>&1; then
VRAW=$(snap list lxd 2>/dev/null | awk '/^lxd /{print $2}' | head -1)
fi
if [ -z "$VRAW" ]; then
echo "UNKNOWN: LXD version not found"
exit 2
fi
major=$(echo "$VRAW" | cut -d. -f1)
minor=$(echo "$VRAW" | cut -d. -f2)
case "$major.$minor" in
4.0)
patched_floor="4.0.15"
;;
5.0)
patched_floor="5.0.11"
;;
5.21)
patched_floor="5.21.9"
;;
6.9|6.10)
patched_floor="6.10.1"
;;
*)
if [ "$major" -gt 6 ] || { [ "$major" -eq 6 ] && [ "$minor" -gt 10 ]; }; then
patched_floor="6.10.1"
else
echo "UNKNOWN: series $major.$minor not covered"
exit 2
fi
;;
esac
if ver_ge "$VRAW" "$patched_floor"; then
echo "PATCHED: LXD $VRAW >= $patched_floor"
exit 0
else
echo "VULNERABLE: LXD $VRAW < $patched_floor"
exit 1
fi