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
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
- https://github.com/nuclio/nuclio/security/advisories/GHSA-m8xg-8xg9-mxhm web
- https://github.com/nuclio/nuclio/pull/4107 web
- https://github.com/nuclio/nuclio/commit/1915cd26d514dcdd487517d4be56673fc02298e0 web
- https://github.com/nuclio/nuclio package
- https://github.com/nuclio/nuclio/releases/tag/1.16.0 web