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-23954

Incus Escape: From Templates to Host Root

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 23, 2026·6 min read·76 visits

Executive Summary (TL;DR)

Incus (an LXD fork) trusted user-supplied paths in container image templates too much. By crafting a malicious image with a specific `metadata.yaml`, an attacker can trick the root-privileged Incus daemon into reading or writing files outside the container rootfs. This is trivially exploitable for host-level Remote Code Execution (RCE).

A critical path traversal and symbolic link vulnerability in the Incus container manager allows privileged container users to escape confinement and execute arbitrary code as root on the host system.

The Hook: Trust Issues in Container Land

In the world of system containers, we often conflate "containment" with "security boundary." Incus, the community-driven fork of LXD, is a powerful tool for managing system containers that feel like full virtual machines. One of its creature comforts is image templating. When you launch a container, Incus doesn't just unpack a tarball; it looks at a metadata.yaml file to perform last-mile customization. It might update /etc/hosts, set a hostname, or inject cloud-init configurations.

Here is the catch: The Incus daemon performs these file operations. The Incus daemon runs as root. And the instructions for what to write and where to write it come from the container image itself.

This architecture creates a classic "Confused Deputy" scenario. The daemon is helpful, privileged, and obedient. If the image asks it to update a file, it does so. The security of the entire host relies on the daemon strictly checking that it isn't being tricked into writing outside the container's sandbox. In CVE-2026-23954, those checks failed spectacularly.

The Flaw: A Tale of Two Paths

The vulnerability lies in internal/server/instance/drivers/driver_lxc.go, specifically within the templateApplyNow function. This function is responsible for iterating through the templates defined in an image's metadata and applying them.

Root Cause Analysis reveals a classic Path Traversal (CWE-22) combined with Improper Link Resolution. When processing a template, the code takes a source file (from the image) and copies it to a target path (inside the container). The logic relied on standard string manipulation to determine these paths.

The fatal error was assuming that filepath.Join is sufficient security. While filepath.Join cleans up dirty paths (resolving ../), it operates purely on the lexical path string. It does not check the physical reality of the filesystem. If an attacker places a symbolic link inside the container image that points to the host's root (/), filepath.Join sees a valid path inside the container, but the operating system follows the symlink out to the host filesystem during the file write operation.

The Code: The Smoking Gun

Let's look at the vulnerable Go code vs. the secure implementation. This highlights why modern file system APIs are critical for security.

The Vulnerable Code: The original code constructed the full path by joining the container's rootfs path with the target template path. It then handed this string directly to os.Create.

// Vulnerable logic in driver_lxc.go
// d.RootfsPath() is the container's safe jail (e.g., /var/lib/incus/containers/foo/rootfs)
// tplPath comes from the attacker-controlled metadata.yaml
 
fullpath := filepath.Join(d.RootfsPath(), strings.TrimLeft(tplPath, "/"))
 
// CRITICAL FLAW: If a component of tplPath is a symlink to /, 
// os.Create follows it out of the jail.
w, err = os.Create(fullpath)

The Fix (Go 1.24 Magic): The patch leverages a new feature in Go 1.24: os.Root. This provides a capability-based file system handle. Instead of operating on global strings, we open a "root" handle to the container directory. Any operations performed relative to this handle are enforced by the OS (using mechanisms like openat2 with RESOLVE_BENEATH) to ensure they cannot escape that directory tree, regardless of symlinks or ../ trickery.

// Patched logic
rootPath, err := os.OpenRoot(d.RootfsPath())
if err != nil {
    return err
}
defer rootPath.Close()
 
// We strip the leading slash but use the root handle to create the file.
// If relPath traverses out via symlinks, this call explicitly fails.
relPath := strings.TrimLeft(tplPath, "/")
w, err = rootPath.Create(relPath)

The Exploit: Escaping the Jail

To exploit this, we don't need memory corruption or complex heap spraying. We just need to be able to import a custom image. This is a privilege usually granted to the incus group.

Step 1: The Trap (Symbolic Link) We create a malicious root filesystem containing a symlink that points to the host's root directory. Inside our image tarball:

ln -s / rootfs/realroot

Step 2: The Map (metadata.yaml) We craft the metadata.yaml to define a template action. We tell Incus: "Hey, when you start this container, please take this innocent file and write it to /realroot/proc/sys/kernel/core_pattern."

Because of the symlink we created in Step 1, /realroot/ actually resolves to the host's root directory. Incus thinks it is writing to /var/lib/incus/containers/poc/rootfs/realroot/..., but the kernel redirects the write to /proc/sys/kernel/core_pattern on the host.

Step 3: The Payload (RCE) We overwrite core_pattern to execute a shell script whenever a program crashes. This is a standard container escape technique.

templates:
  # The exploit target: Host's core_pattern
  /realroot/proc/sys/kernel/core_pattern:
    when: [start]
    template: payload.tpl

Step 4: Execution We import the image and launch it. The moment the container starts, the Incus daemon processes the template, traversing our symlink and overwriting the host's kernel configuration. We then crash a process (e.g., sleep 10 & kill -SIGSEGV %1), causing the kernel to trigger our payload as root.

The Impact: Game Over

The impact here is Critical (CVSS 8.7). While the score is slightly tempered because you need initial access to the incus group (or similar privileges to create images), the result is total system compromise.

This vulnerability allows for:

  1. Arbitrary File Write: As demonstrated, we can overwrite critical system files (/etc/shadow, /etc/ld.so.preload, /usr/bin/*).
  2. Arbitrary File Read: By reversing the logic, we can define a template source using ../ traversal (e.g., template: ../../../../../etc/shadow). Incus will read the host file and copy it into our container, allowing us to steal password hashes or SSH keys.

This effectively blurs the line between "container admin" and "host admin." If you run a multi-tenant environment where users are allowed to bring their own images, you are vulnerable.

The Fix: Remediation Strategies

The fix was released in Incus 6.21.0 (Feature release) and Incus 6.0.6 (LTS release). The primary mitigation is to upgrade immediately.

If you cannot upgrade, you must restrict access to the incus group. Treat any user with incus group membership as if they already have root access to the host—because, with this exploit, they effectively do. Additionally, avoid importing images from untrusted sources or public remotes that you do not control.

For developers, the lesson is clear: Never trust filepath strings. If you are writing file manipulation code in Go, upgrade to 1.24 and use os.OpenRoot for any directory-constrained operations. The filesystem state is volatile; checking a path string before use is a Time-of-Check Time-of-Use (TOCTOU) race condition waiting to happen. Let the OS kernel enforce the boundaries via file descriptors.

Official Patches

IncusCommit fixing the vulnerability by using os.Root

Technical Appendix

CVSS Score
8.7/ 10
CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N

Affected Systems

Incus Container Manager (Feature release <= 6.20)Incus Container Manager (LTS release <= 6.0.5)Linux Systems running vulnerable Incus versions

Affected Versions Detail

Product
Affected Versions
Fixed Version
Incus
Linux Containers
<= 6.0.56.0.6
Incus
Linux Containers
<= 6.20.06.21.0
AttributeDetail
CWE IDCWE-22 (Path Traversal)
CVSS v3.18.7 (High)
Attack VectorAdjacent Network (AV:A)
ImpactConfidentiality High, Integrity High
Exploit StatusPoC Available
PrerequisitesContainer launch permissions (incus group)

MITRE ATT&CK Mapping

T1611Escape to Host
Privilege Escalation
T1543.003Create or Modify System Process: Windows Service
Persistence
CWE-22
Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.

Known Exploits & Detection

Incus Security AdvisoryOfficial advisory containing the PoC details and patch information.

Vulnerability Timeline

Vulnerability Disclosed
2026-01-22
CVE-2026-23954 Assigned
2026-01-22
Patch Released in Incus 6.21.0
2026-01-22

References & Sources

  • [1]GHSA-7f67-crqm-jgh7

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

•2 days ago•CVE-2026-53653
8.7

CVE-2026-53653: Unauthenticated Denial of Service via Unbounded Image Derivative Dimensions in Grav CMS

Grav CMS prior to version 1.7.53 and 2.0.0-rc.8 is vulnerable to an unauthenticated remote denial of service (DoS) vulnerability. By supplying crafted query parameters with extremely large dimensions to image assets, remote unauthenticated attackers can force the server to allocate massive amounts of system memory, leading to kernel Out-Of-Memory (OOM) termination of web worker processes.

Amit Schendel
Amit Schendel
9 views•7 min read
•2 days ago•CVE-2026-53657
8.2

CVE-2026-53657: Privilege Escalation via Overly Permissive Unix Domain Socket in Lima Guest Agent

CVE-2026-53657 is a local privilege escalation vulnerability in Lima (lima-vm/lima) affecting versions prior to 2.1.3 when configured with the QEMU driver. The guest agent daemon, running as root, creates its communication socket `/run/lima-guestagent.sock` with world-writable permissions (0777). This allows unprivileged local users to command the agent to establish arbitrary tunnels, including to privileged local UNIX sockets (like D-Bus). Because the target daemon authenticates the incoming connection using the credentials of the root-owned guest agent (via SO_PEERCRED), unprivileged users can perform root operations, resulting in complete guest VM compromise.

Amit Schendel
Amit Schendel
6 views•9 min read
•2 days ago•CVE-2026-10740
5.3

CVE-2026-10740: Denial of Service in s2n-quic CryptoStream Reassembly

An unauthenticated Denial of Service vulnerability exists in the s2n-quic library's CryptoStream reassembler due to a lack of buffer limits on out-of-order cryptographic frames. An attacker can transmit a crafted CRYPTO frame with an extremely high offset and nominal payload, forcing the receiver to execute unbounded memory allocations and causing service crashes.

Amit Schendel
Amit Schendel
6 views•7 min read
•2 days ago•CVE-2026-55153
7.1

CVE-2026-55153: JNDI Injection and Deserialization Gadget Abuse in mchange-commons-java

A JNDI Injection and Deserialization Gadget vulnerability exists in mchange-commons-java prior to version 0.6.0. The com.mchange.v2.naming.JavaBeanObjectFactory component permits arbitrary class instantiation and setter invocation, allowing attackers to perform Server-Side Request Forgery (SSRF) and remote class loading.

Alon Barad
Alon Barad
7 views•5 min read
•2 days ago•GHSA-8RW6-P7M8-63JP
6.5

GHSA-8RW6-P7M8-63JP: Array Element-Level SELECT Permissions Leak in SurrealDB

SurrealDB versions supporting element-level SELECT permissions on arrays are vulnerable to a logical authorization bypass. Due to an index-shifting error during array filtration, restricted elements can skip permission checks and leak to unauthorized record users.

Alon Barad
Alon Barad
10 views•6 min read
•3 days ago•CVE-2026-12243
7.5

CVE-2026-12243: Incomplete Path Traversal Validation and Percent-Encoding Bypass in NLTK

CVE-2026-12243 is a path traversal vulnerability in the Natural Language Toolkit (NLTK) version 3.9.4. The flaw exists because the input validation routine fails to account for percent-encoded directory traversal sequences like '..%2f' before passing them to urllib.request.url2pathname(), which decodes them into active traversal sequences.

Amit Schendel
Amit Schendel
8 views•8 min read