GitHub Advisoryadvisory · Go

GHSA-m8xg-8xg9-mxhm Nuclio: Missing authorization on project write paths allows any authenticated user to modify or delete any project

HIGH Published 2026-06-04 Modified 2026-06-04 Official page ↗
Aliases
CVE-2026-45730
Ecosystem
Go
Packages
github.com/nuclio/nuclio
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:H
Weaknesses
CWE-862
Reviewed
2026-06-04

Affected packages

• Go github.com/nuclio/nuclio: < 0.0.0-20260513101907-1915cd26d514 → fixed in 0.0.0-20260513101907-1915cd26d514

Description

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). --- Summary Nuclio 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 credentials • The 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 networks • Self-hosted deployment: Dashboard is usually limited to cluster-internal or internal network access • Conservative baseline: authenticated-internal; for public-facing deployments, reachability should be rated higher User interaction required: None • The 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: ``` Before: Authenticated account with zero permissions on target project (OPA correctly denies GET, returns empty list) ↓ After: Can modify or delete any project on the platform Can trigger cascading deletion of all associated Functions, APIGateways, and FunctionEvents Can modify project configuration, affecting NuclioProject CRD in Kubernetes deployments ``` Exploitation difficulty: Very low — four-step attack chain, each step requiring no special technical skill. --- Details Root Cause The read and write paths diverge in how they populate `PermissionOptions.MemberIds`: Read path (correct implementation) — `pkg/dashboard/resource/project.go:87-90` ```go PermissionOptions: opaclient.PermissionOptions{ MemberIds: opa.GetUserAndGroupIdsFromAuthSession(pr.getCtxSession(ctx)), OverrideHeaderValue: request.Header.Get(headers.ProjectsRole), }, ``` Write path Update (vulnerable) — `pkg/dashboard/resource/project.go:194-196` ```go PermissionOptions: opaclient.PermissionOptions{ OverrideHeaderValue: request.Header.Get(headers.ProjectsRole), // MemberIds is not set — OPA check will be skipped }, ``` Write path deleteProject (vulnerable) — `pkg/dashboard/resource/project.go:686-688` ```go PermissionOptions: opaclient.PermissionOptions{ OverrideHeaderValue: request.Header.Get(headers.ProjectsRole), // MemberIds is not set — OPA check will be skipped }, ``` Short-circuit bypass — `pkg/platform/abstract/platform.go:652` ```go func (ap *Platform) FilterProjectsByPermissions(...) ([]platform.Project, error) { if len(permissionOptions.MemberIds) == 0 || len(projects) == 0 { return projects, nil // skips OPA entirely } allowedList, err := ap.QueryOPAMultipleResources(...) } ``` Kubernetes platform write paths (no OPA at all) — `pkg/platform/kube/platform.go:779-793` ```go func (p *Platform) UpdateProject(ctx context.Context, updateProjectOptions *platform.UpdateProjectOptions) error { if err := p.ValidateProjectConfig(ctx, &updateProjectOptions.Project); err != nil { ... } if _, err := p.projectsClient.Update(ctx, updateProjectOptions); err != nil { ... } return nil // no OPA call } func (p *Platform) DeleteProject(ctx context.Context, deleteProjectOptions *platform.DeleteProjectOptions) error { if err := p.ValidateDeleteProjectOptions(ctx, deleteProjectOptions); err != nil { ... } if err := p.projectsClient.Delete(ctx, deleteProjectOptions); err != nil { ... } return nil // no OPA call } ``` Sanitizer Coverage Analysis All 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` ```go func (ap *Platform) ValidateProjectConfig(projectConfig *platform.ProjectConfig) error { if projectConfig.Meta.Name == "" { return ... } // name not empty if err := utils.ValidateLabels(...); err != nil { ... } // labels format if err := utils.ValidateLabels(...); err != nil { ... } // node selector format errorMessages := validation.IsDNS1123Label(...) // DNS naming convention return nil // No identity check, no ownership check, no OPA call } ``` Pure format validation — no identity or resource-ownership checks of any kind. ValidateDeleteProjectOptions (false security check) — `pkg/platform/abstract/platform.go:536-576` ```go func (ap *Platform) ValidateDeleteProjectOptions(ctx context.Context, deleteProjectOptions *platform.DeleteProjectOptions) error { // ... projects, err := ap.platform.GetProjects(ctx, &platform.GetProjectsOptions{ Meta: deleteProjectOptions.Meta, PermissionOptions: deleteProjectOptions.PermissionOptions, // MemberIds still empty! // ... }) // ... if len(projects) == 0 { return nil } // project doesn't exist, exit early // Check for associated functions/API gateways } ``` 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 Comparison Read path (correctly blocks unauthorized access): ``` GET /api/projects → GetAll() [project.go:71] → MemberIds = GetUserAndGroupIdsFromAuthSession() [project.go:88] → platform.GetProjects(MemberIds=[uid, gid1, ...]) → FilterProjectsByPermissions(MemberIds=[uid, gid1, ...]) → OPA filter_allowed called → unauthorized user gets empty list ✓ ``` Write path (authorization bypassed): ``` PUT /api/projects/{id} → Update() [project.go:165] → MemberIds = (not set) [project.go:194] → platform.UpdateProject(MemberIds=[]) → ValidateProjectConfig() ← format-only, no auth check → projectsClient.Update() → project modified, no OPA check DELETE /api/projects → deleteProject() [project.go:663] → MemberIds = (not set) [project.go:686] → platform.DeleteProject(MemberIds=[]) → ValidateDeleteProjectOptions() → inner GetProjects(MemberIds=[]) → OPA bypassed again (false security check) → projectsClient.Delete() → project deleted, no OPA check ``` For reference, the function write path is correctly implemented (`pkg/dashboard/…

Related

Alias · CVE (1)

  • CVE-2026-45730 Nuclio is a "Serverless" framework for Real-Time Events and Data Processing. vulnerability

Weakness · CWE (1)

  • CWE-862 Missing Authorization weakness

References