GHSA-m8xg-8xg9-mxhm Nuclio: Missing authorization on project write paths allows any authenticated user to modify or delete any project
This vulnerability exists in Nuclio Dashboard's project management API, allowing any authenticated user (without membership in the target project) to bypass OPA authorization checks on write paths (`PUT /api/projects/{id}`, `DELETE /api/projects`) and modify or delete any project along with all its associated resources (functions, API gateways, etc.). CWE classification: CWE-862 (Missing Authorization).SummaryNuclio Dashboard correctly enforces OPA-based authorization on the project read path (`GET /api/projects`), populating `MemberIds` in `PermissionOptions` so OPA can filter results by user membership. However, the write paths (`PUT /api/projects/{id}` and `DELETE /api/projects`) construct `PermissionOptions` without setting `MemberIds`. The platform-layer `FilterProjectsByPermissions` function (`pkg/platform/abstract/platform.go:652`) short-circuits when `MemberIds` is empty, bypassing OPA entirely. Any authenticated user who knows a project name can modify or delete that project, triggering cascading deletion of all associated Functions, APIGateways, and FunctionEvents.Affected: Nuclio v1.15.26 (latest Helm release) and HEAD commit e185454 (latest source).Attacker Model**Attacker type**: Authenticated low-privilege tenant (no membership in the target project)**Initial access**:Holds any valid Nuclio Dashboard credentialsThe account has no membership in the target project (OPA correctly denies `GET /api/projects`, returning an empty list)No Kubernetes RBAC permissions required — the vulnerability is triggered at the Dashboard application layer, not via K8s API Server**Attacker location**: Authenticated user; network position depends on deployment:Typical Iguazio/MLRun enterprise deployment: Dashboard is exposed via load balancer to internal or public networksSelf-hosted deployment: Dashboard is usually limited to cluster-internal or internal network accessConservative baseline: authenticated-internal; for public-facing deployments, reachability should be rated higher**User interaction required**: NoneThe attacker directly sends HTTP requests to `PUT /api/projects/{id}` or `DELETE /api/projects` to trigger the vulnerability; no action from the target user is required**Privilege gap**:**Exploitation difficulty**: Very low — four-step attack chain, each step requiring no special technical skill.DetailsRoot CauseThe read and write paths diverge in how they populate `PermissionOptions.MemberIds`:**Read path (correct implementation)** — `pkg/dashboard/resource/project.go:87-90`**Write path Update (vulnerable)** — `pkg/dashboard/resource/project.go:194-196`**Write path deleteProject (vulnerable)** — `pkg/dashboard/resource/project.go:686-688`**Short-circuit bypass** — `pkg/platform/abstract/platform.go:652`**Kubernetes platform write paths (no OPA at all)** — `pkg/platform/kube/platform.go:779-793`Sanitizer Coverage AnalysisAll validation functions on the write path are format-only and contain no identity or ownership-based authorization checks:**ValidateProjectConfig** — `pkg/platform/abstract/platform.go:854-879`Pure format validation — no identity or resource-ownership checks of any kind.**ValidateDeleteProjectOptions (false security check)** — `pkg/platform/abstract/platform.go:536-576`This function calls `GetProjects` passing along the `PermissionOptions` inherited from the caller — with `MemberIds` still empty. The inner OPA query is therefore also bypassed by the same short-circuit. It appears to validate project existence and associated resources, but the identity check is silently absent. This is a false security check.**Conclusion**: Two validation layers exist on the write path; both are format-only. No identity-based authorization check exists anywhere in the write path, leaving the entire defense chain ineffective at the application layer.Call Chain ComparisonRead path (correctly blocks unauthorized access):Write path (authorization bypassed):For reference, the function write path is correctly implemented (`pkg/dashboard/resource/function.go:564-566`), confirming this is an omission specific to project write paths:PoC (Proof of Concept)Environment SetupThis verification uses the Nuclio Dashboard binary compiled from source, paired with a mock Iguazio auth server and a mock OPA server. No Kubernetes cluster is required.**Step 1: Prepare working directory****Step 2: Build Nuclio Dashboard binary from source (HEAD commit e185454)****Step 3: Deploy mock Iguazio Auth + OPA server**Save as `/tmp/nuclio-vul001-test/mock_server.py`:Save as `/tmp/nuclio-vul001-test/platform.yaml`:Start the mock servers:**Step 4: Start Nuclio Dashboard****Step 5: Verify authentication is active**Actual output:Exploitation Steps**Step 1: Admin creates a test project (HTTP 201)**Output: `201`**Step 2: Reader attempts GET — OPA correctly denies (HTTP 200, empty result)**Output: `{}`Dashboard log (OPA is invoked on read path):Mock OPA server log:The read path correctly blocks the reader.**Step 3: Reader exploits vulnerable PUT path — unauthorized modification (HTTP 204)**Output: `204`**Expected: 403 Forbidden. Actual: 204 No Content — unauthorized modification succeeded.**Dashboard log (no OPA entries on the PUT path — contrast with Step 2):**Step 4: Admin verifies modification persisted**Output:**Step 5: Reader exploits vulnerable DELETE path — unauthorized deletion (HTTP 204)**Output: `204`**Expected: 403 Forbidden. Actual: 204 No Content — unauthorized deletion succeeded.**Dashboard log (no OPA entries on the DELETE path):**Step 6: Admin confirms project is gone**Output: `404`Expected Result| Operation | User | OPA Called | HTTP Status | Result |
|-----------|------|-----------|------------|--------|
| GET /api/projects | reader | Yes | 200 (empty) | Read path protected correctly |
| PUT /api/projects/{id} | reader | **No** | **204** | **Vulnerable: unauthorized modification** |
| DELETE /api/projects | reader | **No** | **204** | **Vulnerable: unauthorized deletion** |
| GET /api/projects/{id} | admin | — | 200 | Modification confirmed persisted |
| GET /api/projects/{id} | admin | — | 404 | Deletion confirmed |ImpactMulti-Tenant Isolation Breach (Trust Boundary)This vulnerability is a **Multi-Tenant Isolation Breach** — the attacker crosses the Nuclio Dashboard tenant isolation boundary to perform write operations on resources they have no access to:**Confidentiality (C:L)**The read path is protected by OPA; the attacker cannot enumerate project contents via GET. However, the attacker can infer project existence by sending PUT/DELETE requests and observing response codes (204 vs 404), creating a side-channel information leak. The actual project data content is not directly readable.**Integrity (I:H)**Any authenticated user can modify the configuration of any project on the platform, including:Project description and metadataIn Kubernetes deployments: NuclioProject CRD fields that affect Nuclio controller reconciliation behavior, such as `DefaultFunctionNodeSelector` and `DefaultFunctionPriorityClassName`, which influence subsequent function deployments under the project**Availability (A:H)**Any authenticated user can delete any project, triggering cascading deletion of all associated Functions, APIGateways, and FunctionEvents. These operations are irreversible through normal means.Kubernetes Deployment Impact AnalysisIn Kubernetes deployments, each Nuclio project maps to a NuclioProject CRD. The Nuclio controller (`nuclio-controller`) continuously watches NuclioProject resources and reconciles state:**Modification impact**: NuclioProject Spec fields such as `DefaultFunctionNodeSelector` and `DefaultFunctionPriorityClassName` affect deployment templates for functions under that project when reconciled. An attacker modifying these fields can influence the execution environment of functions subsequently deployed under the compromised project.**Deletion impact**: Deleting a NuclioProject CRD triggers the controller to cascade-delete all associated NuclioFunction, NuclioAPIGateway, and related CRD resources in the namespace.The currently known attack path does not directly modify ServiceAccount or ClusterRoleBinding resources. Credential theft risk is low on the direct path, but the indirect impact on function execution environments warrants monitoring.Typical Attack ScenariosIn a multi-tenant Nuclio environment, Tenant B with a low-privilege account can modify or delete Tenant A's projects by knowing the project name (obtainable via guessing or internal information)An attacker systematically deletes all projects on the platform, causing platform-wide service disruption not bounded by namespaceModifying another tenant's project configuration in Kubernetes environments affects function deployment behavior (node selection, resource quotas)Severity**Scope Justification (S:U vs S:C)**The current score uses S:U. Under CVSS 3.1, S:C requires that the affected component operates in a different authorization scope from the vulnerable component. Here, both the attacker's session and the victim's project resources fall within the same Nuclio Dashboard authorization domain; the tenant isolation is a logical boundary within the application rather than a separate authorization authority. From a strict CVSS 3.1 perspective, S:U is more accurate.However, since the vulnerability enables one tenant to affect another tenant's resources, an argument can be made for S:C from the perspective that the attacker's authorization context and the victim's resource authority are logically distinct. The Scope selection rationale should be noted in the submission for the recipient to make a final determination.Affected VersionsNuclio HEAD commit e185454 (latest source, dynamically verified)Nuclio v1.15.26 (latest Helm chart release, same code path confirmed)All versions with iguazio or iguazio-v4 authentication enabledDeployments using the default `nop` authentication mode are not affected, but production Iguazio environments always use iguazio authentication.Patched VersionsNo patched version available as of 2026-05-06.WorkaroundsUntil an official fix is released:**Network-level restriction**: Use firewall rules or Kubernetes NetworkPolicy to restrict Dashboard API access to trusted clients only**Credential control**: Strictly limit distribution of Nuclio Dashboard credentials to minimize low-privilege account exposure**Audit logging**: Enable access logging on `PUT /api/projects/` and `DELETE /api/projects` paths and monitor for anomalous operationsReferencesVulnerable code (missing MemberIds on write path): `pkg/dashboard/resource/project.go:194`, `:686`Short-circuit bypass: `pkg/platform/abstract/platform.go:652`False security check: `pkg/platform/abstract/platform.go:536-576`Format-only validation (no auth check): `pkg/platform/abstract/platform.go:854-879`Kubernetes platform write paths (no OPA): `pkg/platform/kube/platform.go:779-793`Correct read path implementation (reference): `pkg/dashboard/resource/project.go:87-90`Correct function write path implementation (reference): `pkg/dashboard/resource/function.go:564-566`Nuclio GitHub repository: https://github.com/nuclio/nuclio
CVSS v3.1 score: 8.3