LXD and Incus mTLS Authentication Bypass (CVE-2026-112816)
LXD and Incus mTLS authentication bypass lets network attackers impersonate trusted clients using public certificates. Check exposure and fixed versions.
TL;DR
- A flaw in the HTTPS API of Canonical LXD, MicroCloud and Incus lets a network attacker authenticate as any trusted client without that client's private key. The Incus project reported it and Canonical confirmed LXD and MicroCloud affected; Canonical published its advisory on October 28, 2026.
- An affected, unpatched daemon is exposed if an attacker can reach its HTTPS API and obtain a trusted identity's public certificate. Incus exposes server certificates during TLS handshakes; MicroCloud's advisory describes intercepting a joining member's certificate. No authentication, privileges or user interaction are required.
- Canonical's CVE record rates it Critical, CVSS v4.0 10.0. No exploitation is known, and it is not in CISA's Known Exploited Vulnerabilities catalog as of November 1, 2026. The cited vendor advisories do not link a public proof of concept.
- Update LXD and MicroCloud with
sudo snap refresh lxdandsudo snap refresh microcloud, and move Incus to 7.6.0. Restricting who can reach the HTTPS listener is the recommended stopgap, and it is not a fix.
Am I affected?
You are exposed when all of these hold:
- A daemon in the affected ranges below is running: LXD, MicroCloud or Incus.
- Its HTTPS API listens on a network address an attacker can reach. A standalone LXD daemon serves a local Unix socket by default, and it binds the network listener only when one is configured, per its endpoints source. Clusters and remote clients require the network API.
- The attacker can obtain the public certificate of a trusted identity. Server certificates are returned by every TLS handshake, so the most direct attack path needs no prior access at all.
The Incus advisory states the flawed pattern has been present since the initial release, so Incus installations older than 7.6.0 are affected.
| Branch | Affected versions | Fixed version |
|---|---|---|
| LXD 6.x | 6.9.0 to 6.10.0 | 6.10.1 (October 29, 2026) |
| LXD 5.21.x LTS | through 5.21.8 | 5.21.9 (October 29, 2026) |
| LXD 5.0.x LTS | through 5.0.10 | 5.0.11 (October 29, 2026) |
| LXD 4.0.x LTS | through 4.0.14 | 4.0.15 (October 29, 2026) |
| Incus | all releases before 7.6.0, through 7.5.x | 7.6.0 (October 30, 2026) |
| MicroCloud 3.x | releases before 3.4.1 | 3.4.1 (October 29, 2026) |
| MicroCloud 2.x | releases before 2.1.5 | 2.1.5 (October 29, 2026) |
Canonical distributes LXD and MicroCloud as snaps; the Ubuntu archive carries no affected LXD package, and Ubuntu's own tracker rates the issue Medium. The fixed releases listed above are the snap versions per Canonical's advisory.
Check what you run and whether the network API is on:
snap list lxd
lxc version
lxc config get core.https_address
lxc config get cluster.https_address
snap list microcloud
Check both API and cluster listener addresses; an empty API address alone does not rule out a cluster listener. Incus uses the same configuration keys:
incus version
incus config get core.https_address
incus config get cluster.https_address
How do I fix it?
Update every LXD and MicroCloud daemon to the fixed version for its channel, and update Incus to 7.6.0:
- Refresh the snaps:
sudo snap refresh lxdandsudo snap refresh microcloud. - Confirm the daemon actually runs a fixed version:
snap list lxdpluslxc version. Canonical notes all LXD point releases were in progressive rollout from candidate to stable when it published the advisory, so re-check after refreshing rather than assume the fix arrived. - Update Incus through its package channel to 7.6.0, which also fixes 17 other security issues per its release announcement.
There is no configuration workaround. The recommended stopgap is to restrict network access to the HTTPS listener to trusted hosts, as the Incus advisory recommends until the update lands. Its limit is plain: the flaw stays in the daemon, and any untrusted path to the listener leaves it open.
What is the root cause?
The trust checks compared every certificate the client sent against the trust store. A TLS handshake only proves the client holds the private key of the first certificate in the chain, and the rest of the chain is client-controlled. The LXD and Incus HTTPS listener asks for a client certificate with Go's tls.RequestClientCert, which requests the chain without verifying it.
The Incus daemon carried the clearest form of the bug, in Authenticate in cmd/incusd/daemon.go before version 7.6.0:
// Allow internal cluster traffic by checking against the trusted certficates.
if r.TLS != nil {
for _, i := range r.TLS.PeerCertificates {
trusted, fingerprint := localUtil.CheckTrustState(*i, trustedCerts[certificate.TypeServer], d.endpoints.NetworkCert(), false)
if trusted {
return true, fingerprint, "cluster", nil, nil
}
}
}
The same loop over r.TLS.PeerCertificates ran for regular client certificates and for metrics certificates, where i is each presented certificate in turn. r.TLS.PeerCertificates is every certificate the client handed over, in the order the client chose. CheckTrustState compares one certificate against the trust-store entries, so the loop turns a chain the client assembled into a list of candidate identities.
Appending a trusted identity's public certificate as an extra chain element therefore authenticates the attacker as that identity. The leaf certificate proves who the attacker is; the appended certificate decides who the server believes they are.
How is it exploited?
The attack needs one TLS connection and one public certificate:
- The attacker captures a public certificate of a trusted identity. A server certificate falls out of any TLS handshake with the daemon, so no prior access is needed. A client certificate can be read through the certificates API by any trusted client, or collected from any server that client connected to.
- The attacker connects to the HTTPS API with their own certificate and private key, and appends the captured public certificate to the presented chain.
- The handshake succeeds, because the listener only requests the chain and verifies nothing beyond the leaf's key.
- The trust loop walks the presented chain, matches the appended certificate against a trust-store entry, and authenticates the attacker as that identity.
The impersonation also works against the self-service certificate paths. The advisory states a client could renew or delete any trust-store entry. It also states the unverified chain reached the authorization scriptlet, letting a client feed attacker-chosen certificates into scriptlet authorization decisions. The cited vendor advisories do not link a public proof of concept. None of this requires more than network reachability.
How does the attack flow?
One connection to the HTTPS listener, with the trusted identity's public certificate placed in the chain, is enough to become that identity.
the HTTPS API"] --> B["Own leaf certificate plus
a trusted identity's public
certificate in the chain"] B --> C["Handshake requests the chain
and verifies only the leaf key"] C --> D["Trust loop matches
the appended certificate
against the trust store
missing check"] D --> E["Authenticated as
the trusted identity"] E --> F["Cluster and VM control,
database gateway,
possibly root on the host"]
What can an attacker do?
The attacker inherits everything the impersonated identity can do, on the affected products:
- Full access to the cluster and its managed virtual machines, per the CVE record. Canonical states that when the impersonated user is privileged, the attacker may gain root access to the host machine.
- Access to the database gateway by presenting the server's own certificate, and internal cluster access by presenting another member's certificate on a cluster, per the Incus advisory. Impersonating a cluster member bypasses authorization entirely.
- Renewal and deletion of any trust-store entry through the self-service paths. The same flaw feeds the authorization scriptlet, so a client can influence scriptlet-based authorization decisions. This includes token or OpenID Connect clients, which can still present an arbitrary certificate during the handshake.
- Impersonation of the agent connection between the host and virtual machines, which carries the same flaw.
In MicroCloud, Canonical warns that an attacker who can intercept the public TLS certificate of a cluster member while it joins can then authenticate as that member. The conditions stay the same: network reachability of the API plus a public certificate, with no privileges and no user interaction.
Why does the fix work?
The public reference fix is Incus commit 8381e54c3631c627d7ecdec03945bca14d0bd542, "Only trust the key-proven client certificate", authored on October 13, 2026 by Stéphane Graber:
+ // The TLS listener only proves possession of the first peer certificate's key, so the rest of
+ // the presented chain is attacker-controlled and must never be matched against the trust store.
+ var peerCert *x509.Certificate
+ if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
+ peerCert = r.TLS.PeerCertificates[0]
+ }
The trust checks then run against peerCert only, replacing every loop over r.TLS.PeerCertificates:
- if r.TLS != nil {
- for _, i := range r.TLS.PeerCertificates {
- trusted, fingerprint := localUtil.CheckTrustState(*i, trustedCerts[certificate.TypeServer], d.endpoints.NetworkCert(), false)
- if trusted {
- return true, fingerprint, "cluster", nil, nil
- }
- }
- }
+ if peerCert != nil {
+ trusted, fingerprint := localUtil.CheckTrustState(*peerCert, trustedCerts[certificate.TypeServer], d.endpoints.NetworkCert(), false)
+ if trusted {
+ return true, fingerprint, "cluster", nil, nil
+ }
+ }
An appended certificate can no longer match anything, because only the leaf the handshake actually verified is consulted. The commit applies the same rule in every trust path the advisory lists. That covers the API authentication, the certificate enrollment and self-service renewal and deletion, the host-to-VM agent connection on both sides, the authorization scriptlet, and cluster traffic.
For LXD and MicroCloud, Canonical's advisory describes the same correction, and the fixed releases listed in "Am I affected?" carry it.
How do I check if I was compromised?
The vendor advisories do not publish indicators of compromise. An unchanged trust store does not rule out impersonation: an attacker can use an existing trusted identity without creating a new entry.
Start by reviewing the trust store and cluster membership for unexpected entries:
lxc config trust list
lxc cluster list
Review each trust-store entry for an unexpected name, type or project set. Pay particular attention to entries that were renewed, since the self-service renewal path is part of the flaw. If a privileged identity could have been impersonated on a host, treat that host as compromised. Assess all credentials accessible from the host, including private keys, and rotate any that may have been exposed during a compromise. Rebuild affected hosts when required by your incident response process.
Timeline
The Incus fix commit was authored 17 days before the CVE record was published. An author timestamp does not establish when the commit became public.
- 2023-07-22: The Incus repository is created as a fork of LXD. The Incus advisory states the flawed pattern has been present since the initial release.
- 2026-10-13: Stéphane Graber authors the Incus fix, commit
8381e54c3631c627d7ecdec03945bca14d0bd542. - 2026-10-19: Canonical reserves CVE-2026-112816.
- 2026-10-21: Canonical announces LXD 6.10.1, the first fixed release on the 6.x branch.
- 2026-10-28: Canonical publishes its security advisory with the fixed snap versions for LXD and MicroCloud.
- 2026-10-29: Incus publishes GHSA-xg75-xf37-cph9. The fixed LXD and MicroCloud snap releases are dated October 29, 2026.
- 2026-10-30: The CVE record is published and Incus 7.6.0 is released. CISA's ADP records no known exploitation, dated October 30, 2026.
FAQ
Why does the TLS handshake not prove the whole chain?
The listener asks for a client certificate with Go's tls.RequestClientCert, which requests the chain but does not verify it. The handshake proves only that the client holds the private key of the first certificate in the chain; every later certificate is data the client chose to attach.
Is a default standalone LXD install exposed?
No. A standalone daemon serves its local Unix socket. It binds the HTTPS listener only when an administrator configures a network address, so the default install is not reachable over the network. Clusters and any remote lxc client need that network API.
Do I need to rotate my certificates after patching?
Public certificate disclosure alone does not require rotation: these certificates are not secrets. Patching closes the authentication bypass. If an attacker obtained host access, assess private-key and other credential exposure separately, rotate compromised credentials, and review the trust store for unauthorized changes.
Are the LXD and Incus flaws the same bug?
They share one mechanism in two codebases with a common lineage. Stéphane Graber, who created both LXD and Incus, reported it; Incus fixed it in 7.6.0 and Canonical fixed LXD and MicroCloud in the releases listed above. Canonical's advisory covers LXD and MicroCloud, and the Incus advisory is published without a CVE id.
Is it exploited in the wild?
No exploitation is known. CISA's ADP assessed exploitation as none on October 30, 2026, and the flaw is not in CISA's Known Exploited Vulnerabilities catalog as of November 1, 2026. The cited vendor advisories do not link a public proof of concept.
Find your exposed LXD and Incus hosts with Ostorlab
Ostorlab's attack surface discovery inventories your internet-facing hosts, so you can find which of your LXD, Incus and MicroCloud daemons expose the HTTPS API and patch those first.
References
- CVE-2026-112816 record, Canonical CNA, CVSS v4.0 10.0: https://www.cve.org/CVERecord?id=CVE-2026-112816 (checked November 1, 2026)
- Canonical security advisory with the fixed snap versions: https://discourse.ubuntu.com/t/security-advisory-critical-vulnerability-found-in-canonical-lxd-and-microcloud/90557 (published October 28, 2026; checked November 1, 2026)
- Incus advisory GHSA-xg75-xf37-cph9, CVSS v3.1 10.0: https://github.com/lxc/incus/security/advisories/GHSA-xg75-xf37-cph9 (published October 29, 2026; checked November 1, 2026)
- Incus fix commit "Only trust the key-proven client certificate": https://github.com/lxc/incus/commit/8381e54c3631c627d7ecdec03945bca14d0bd542 (authored October 13, 2026; checked November 1, 2026)
- LXD 6.10.1 release announcement: https://discourse.ubuntu.com/t/lxd-6-10-1-lts-has-been-released/90024 (published October 21, 2026; checked November 1, 2026)
- Incus 7.6 release announcement, 18 security fixes: https://discuss.linuxcontainers.org/t/incus-7-6-has-been-released/27462 (published October 30, 2026; checked November 1, 2026)
- Ubuntu tracker page for CVE-2026-112816, archive package status and Medium priority: https://ubuntu.com/security/CVE-2026-112816 (checked November 1, 2026)
- LXD endpoints source, local Unix socket by default and the configured HTTPS listener: https://github.com/canonical/lxd/blob/lxd-6.10.1/lxd/endpoints/endpoints.go (checked November 1, 2026)
- CISA Known Exploited Vulnerabilities catalog, feed checked for CVE-2026-112816: https://www.cisa.gov/known-exploited-vulnerabilities-catalog (checked November 1, 2026)
- The Hacker News, "CVSS 10.0 LXD, MicroCloud Flaw Lets Attackers Impersonate Trusted Clients Without a Private Key": https://thehackernews.com/2026/11/critical-lxd-and-microcloud-flaw-cvss.html (published November 1, 2026; checked November 1, 2026)