VYPR
High severity7.7NVD Advisory· Published Jun 10, 2026· Updated Jun 10, 2026

CVE-2026-49823

CVE-2026-49823

Description

Fission is an open-source, Kubernetes-native serverless framework that simplifies the deployment of functions and applications on Kubernetes. Prior to version 1.24.0, a Fission Function spec carries three reference types — Secret, ConfigMap, and Package. The first two were namespace-validated by the admission webhook; PackageRef.Namespace was not. This issue has been patched in version 1.24.0.

Affected products

2
  • Fission/Fissionreferences2 versions
    (expand)+ 1 more
    • (no CPE)
    • (no CPE)range: <1.24.0

Patches

1
80e7ba55228e

Reject cross-namespace Environment + Package references in Function (… (#3389)

https://github.com/fission/fissionSanket SudakeMay 23, 2026via body-scan-shorthand
4 files changed · +160 0
  • pkg/executor/executortype/newdeploy/newdeploymgr.go+13 0 modified
    @@ -270,6 +270,11 @@ func (deploy *NewDeploy) IsValid(ctx context.Context, fsvc *fscache.FuncSvc) boo
     
     // RefreshFuncPods deletes pods related to the function so that new pods are replenished
     func (deploy *NewDeploy) RefreshFuncPods(ctx context.Context, logger logr.Logger, f fv1.Function) error {
    +	// Defence in depth for GHSA-cvw6-gfvv-953q — see fnCreate for context.
    +	if envNs := f.Spec.Environment.Namespace; envNs != "" && envNs != f.Namespace {
    +		return fmt.Errorf("cross-namespace environment reference is not allowed: fn.namespace=%s env.namespace=%s",
    +			f.Namespace, envNs)
    +	}
     
     	env, err := deploy.fissionClient.CoreV1().Environments(f.Spec.Environment.Namespace).Get(ctx, f.Spec.Environment.Name, metav1.GetOptions{})
     	if err != nil {
    @@ -427,6 +432,14 @@ func (deploy *NewDeploy) deleteFunction(ctx context.Context, fn *fv1.Function) e
     }
     
     func (deploy *NewDeploy) fnCreate(ctx context.Context, fn *fv1.Function) (*fscache.FuncSvc, error) {
    +	// Defence in depth for GHSA-cvw6-gfvv-953q — primary defence is the
    +	// admission webhook in pkg/webhook/function.go, but a stale Function
    +	// from a pre-webhook upgrade window (or failurePolicy=ignore) could
    +	// still reach this path.
    +	if envNs := fn.Spec.Environment.Namespace; envNs != "" && envNs != fn.Namespace {
    +		return nil, fmt.Errorf("cross-namespace environment reference is not allowed: fn.namespace=%s env.namespace=%s",
    +			fn.Namespace, envNs)
    +	}
     	cleanupFunc := func(ctx context.Context, ns string, name string) {
     		err := deploy.cleanupNewdeploy(ctx, ns, name)
     		if err != nil {
    
  • pkg/executor/executortype/poolmgr/gpm.go+9 0 modified
    @@ -586,6 +586,15 @@ func (gpm *GenericPoolManager) getFunctionEnv(ctx context.Context, fn *fv1.Funct
     	var env *fv1.Environment
     	otelUtils.SpanTrackEvent(ctx, "getFunctionEnv", otelUtils.GetAttributesForFunction(fn)...)
     
    +	// Defence in depth for GHSA-cvw6-gfvv-953q — the admission webhook
    +	// already rejects this at submit time, but a stale Function object
    +	// from an upgrade-before-webhook-restart window (or a cluster running
    +	// with failurePolicy=ignore) could still reach this path.
    +	if envNs := fn.Spec.Environment.Namespace; envNs != "" && envNs != fn.Namespace {
    +		return nil, fmt.Errorf("cross-namespace environment reference is not allowed: fn.namespace=%s env.namespace=%s",
    +			fn.Namespace, envNs)
    +	}
    +
     	// Cached ?
     	// TODO: the cache should be able to search by <env name, fn namespace> instead of function metadata.
     	result, err := gpm.functionEnv.Get(crd.CacheKeyURFromMeta(&fn.ObjectMeta))
    
  • pkg/webhook/function.go+19 0 modified
    @@ -61,6 +61,25 @@ func (r *Function) Validate(new *v1.Function) error {
     			return v1.AggregateValidationErrors("Function", err)
     		}
     	}
    +	// Cross-namespace EnvironmentRef closes GHSA-cvw6-gfvv-953q. An empty
    +	// namespace remains accepted — the Fission CLI populates it with the
    +	// function's own namespace at creation time (pkg/fission-cli/cmd/function/
    +	// create.go), and downstream controllers tolerate empty via
    +	// DefaultNSResolver. Rejecting only the explicit cross-namespace value is
    +	// sufficient for this advisory; defaulting an empty namespace at admission
    +	// is a separate hardening track tracked outside this fix.
    +	if envRef := new.Spec.Environment; envRef.Namespace != "" && envRef.Namespace != new.Namespace {
    +		err := fmt.Errorf("environment's namespace [%s] and function's namespace [%s] are different; cross-namespace Environment reference is not allowed",
    +			envRef.Namespace, new.Namespace)
    +		return v1.AggregateValidationErrors("Function", err)
    +	}
    +	// Cross-namespace PackageRef closes GHSA-3r8v-2xmj-5c39. Same shape as
    +	// the EnvironmentRef check above, including the empty-is-accepted rule.
    +	if pkgRef := new.Spec.Package.PackageRef; pkgRef.Namespace != "" && pkgRef.Namespace != new.Namespace {
    +		err := fmt.Errorf("package's namespace [%s] and function's namespace [%s] are different; cross-namespace Package reference is not allowed",
    +			pkgRef.Namespace, new.Namespace)
    +		return v1.AggregateValidationErrors("Function", err)
    +	}
     
     	if err := new.Validate(); err != nil {
     		return v1.AggregateValidationErrors("Function", err)
    
  • pkg/webhook/function_test.go+119 0 added
    @@ -0,0 +1,119 @@
    +/*
    +Copyright 2026.
    +
    +Licensed under the Apache License, Version 2.0 (the "License");
    +you may not use this file except in compliance with the License.
    +You may obtain a copy of the License at
    +
    +    http://www.apache.org/licenses/LICENSE-2.0
    +*/
    +
    +package webhook
    +
    +import (
    +	"strings"
    +	"testing"
    +
    +	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    +
    +	v1 "github.com/fission/fission/pkg/apis/core/v1"
    +)
    +
    +// makeValidFunction returns a Function object that satisfies v1.Function.Validate()
    +// so the cross-namespace branches are the only thing under test. The caller may
    +// override the Environment / PackageRef namespaces to exercise the rejects.
    +func makeValidFunction(fnNs, envNs, pkgNs string) *v1.Function {
    +	return &v1.Function{
    +		ObjectMeta: metav1.ObjectMeta{
    +			Name:      "fn-1",
    +			Namespace: fnNs,
    +		},
    +		Spec: v1.FunctionSpec{
    +			Environment: v1.EnvironmentReference{
    +				Name:      "env-1",
    +				Namespace: envNs,
    +			},
    +			Package: v1.FunctionPackageRef{
    +				PackageRef: v1.PackageRef{
    +					Name:      "pkg-1",
    +					Namespace: pkgNs,
    +				},
    +			},
    +			InvokeStrategy: v1.InvokeStrategy{
    +				StrategyType: v1.StrategyTypeExecution,
    +				ExecutionStrategy: v1.ExecutionStrategy{
    +					ExecutorType: v1.ExecutorTypePoolmgr,
    +				},
    +			},
    +		},
    +	}
    +}
    +
    +func TestFunctionWebhook_Validate_CrossNamespaceEnvironment(t *testing.T) {
    +	cases := []struct {
    +		name         string
    +		fnNs         string
    +		envNs        string
    +		wantRejected bool
    +	}{
    +		{name: "empty env.namespace is accepted", fnNs: "default", envNs: "", wantRejected: false},
    +		{name: "same namespace is accepted", fnNs: "default", envNs: "default", wantRejected: false},
    +		{name: "cross namespace is rejected", fnNs: "ns-attacker", envNs: "ns-victim", wantRejected: true},
    +		{name: "cross namespace rejected even when fn in kube-system", fnNs: "kube-system", envNs: "default", wantRejected: true},
    +	}
    +
    +	r := &Function{}
    +	for _, tc := range cases {
    +		t.Run(tc.name, func(t *testing.T) {
    +			err := r.Validate(makeValidFunction(tc.fnNs, tc.envNs, tc.fnNs))
    +			if tc.wantRejected {
    +				if err == nil {
    +					t.Fatalf("expected rejection, got nil")
    +				}
    +				if !strings.Contains(err.Error(), "Environment reference") {
    +					t.Fatalf("error should reference cross-namespace Environment, got: %v", err)
    +				}
    +				if !strings.Contains(err.Error(), tc.envNs) || !strings.Contains(err.Error(), tc.fnNs) {
    +					t.Fatalf("error should mention both namespaces (%q and %q), got: %v", tc.fnNs, tc.envNs, err)
    +				}
    +			} else if err != nil {
    +				t.Fatalf("expected acceptance, got: %v", err)
    +			}
    +		})
    +	}
    +}
    +
    +func TestFunctionWebhook_Validate_CrossNamespacePackage(t *testing.T) {
    +	cases := []struct {
    +		name         string
    +		fnNs         string
    +		pkgNs        string
    +		wantRejected bool
    +	}{
    +		{name: "empty pkg.namespace is accepted", fnNs: "default", pkgNs: "", wantRejected: false},
    +		{name: "same namespace is accepted", fnNs: "default", pkgNs: "default", wantRejected: false},
    +		{name: "cross namespace is rejected", fnNs: "ns-attacker", pkgNs: "ns-victim", wantRejected: true},
    +	}
    +
    +	r := &Function{}
    +	for _, tc := range cases {
    +		t.Run(tc.name, func(t *testing.T) {
    +			// Keep env.Namespace aligned with fn.Namespace so only the
    +			// package-ref branch can trigger the cross-ns reject.
    +			err := r.Validate(makeValidFunction(tc.fnNs, tc.fnNs, tc.pkgNs))
    +			if tc.wantRejected {
    +				if err == nil {
    +					t.Fatalf("expected rejection, got nil")
    +				}
    +				if !strings.Contains(err.Error(), "Package reference") {
    +					t.Fatalf("error should reference cross-namespace Package, got: %v", err)
    +				}
    +				if !strings.Contains(err.Error(), tc.pkgNs) || !strings.Contains(err.Error(), tc.fnNs) {
    +					t.Fatalf("error should mention both namespaces (%q and %q), got: %v", tc.fnNs, tc.pkgNs, err)
    +				}
    +			} else if err != nil {
    +				t.Fatalf("expected acceptance, got: %v", err)
    +			}
    +		})
    +	}
    +}
    

Vulnerability mechanics

Root cause

"The Fission Function admission webhook did not validate the namespace of PackageRef, allowing cross-namespace access."

Attack vector

An attacker with `functions.fission.io/create` permission in their namespace can create a Fission Function. By setting the `spec.package.packageref.namespace` to a victim's namespace, the attacker can cause the function to read a Package from that namespace [ref_id=1]. This allows the attacker to access the victim's source code and embedded credentials, as the fission-fetcher service account has cluster-wide `get packages` permission [ref_id=2].

Affected code

The vulnerability lies in the Fission Function admission webhook, specifically in the `pkg/webhook/function.go::Validate` file. The fix was implemented in pull request #3389 [ref_id=1].

What the fix does

The patch modifies the admission webhook to reject Fission Functions where `spec.package.packageref.namespace` does not match the function's own namespace [ref_id=1]. This prevents the confused deputy primitive where a function in one namespace could reference a Package in another. The fix mirrors prior validation for Secret and ConfigMap references [ref_id=1].

Preconditions

  • authAttacker must have `functions.fission.io/create` permission in their namespace.
  • inputAttacker must be able to create a Fission Function with a `spec.package.packageref.namespace` set to a different namespace.

Generated on Jun 10, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

3

News mentions

1