A tenant with permission to create exactly one namespaced Kubernetes object — nothing cluster-scoped, nothing outside their own project — could walk out with root on the node underneath them. That's the entire story of CVE-2026-50566, a 9.9-CVSS vulnerability in Fission, the Kubernetes-native serverless framework, patched in version 1.24.0. No stolen credentials, no supply-chain compromise, no zero-day in the container runtime. Just an RBAC grant that looked ordinary and a merge function that skipped a step it should never have skipped.
The bug is worth reading closely, not because Fission did something uniquely careless, but because the exact shape of the mistake — RBAC scoping treated as if it were sandbox isolation — is a mistake almost every platform that schedules other people's code onto shared nodes is one code path away from repeating.
What Fission actually lets a tenant touch
Fission runs functions on Kubernetes by wrapping them in an Environment custom resource — effectively a pod template that says "here's the container image and settings any function using this environment should run with." Two of Fission's executor modes, PoolManager and NewDeploy, take that Environment spec and use it to build the actual pods that execute tenant code, keeping a warm pool around so a function invocation doesn't pay a cold-start container-creation cost.
Those pods land in a shared fission-function namespace (or the builder namespace, for the container-build path) and are created by the executor's own service account — which needs meaningfully more privilege than any individual tenant, because it's the thing provisioning workloads on their behalf. That gap between "what the tenant is authorized to submit" and "what privilege the thing executing on their behalf holds" is precisely where this class of bug lives.
Critically, the RBAC permission required to touch an Environment resource — environments.fission.io create/update — is a routine, namespace-scoped grant. It's the kind of permission a self-hosted multi-tenant platform hands out by default to let any onboarded tenant define what their functions run in. Nothing about holding it looks like a privileged operation.
The exact bypass: one field skipped the sanitizer
Fission had already been through a round of PodSpec hardening — call it round 4 — that added validation to strip dangerous settings (hostNetwork, hostPID, hostIPC, privileged, arbitrary serviceAccountName) out of the PodSpecs tenants could supply via spec.runtime.podSpec, spec.builder.podSpec, and a function's own spec.podSpec. That sanitizer runs inside MergePodSpec, the function responsible for combining a tenant-supplied PodSpec with the one the executor builds.
CVE-2026-50566 is what the advisory describes as a follow-up bypass of that same hardening. The Environment CRD also exposes a second, narrower field — spec.runtime.container and spec.builder.container — a standalone Container object (not a full PodSpec) that a tenant can use to set fields like image, command, or, notably, securityContext directly on the function container. That field gets merged in through a different path: MergeContainer().
Here's the actual defect. MergeContainer() performed no sanitization of its own — it simply merged the tenant-supplied Container object in as-is. The sanitizer that would have stripped a privileged: true or allowPrivilegeEscalation: true securityContext only runs inside MergePodSpec, and MergePodSpec is only invoked when a tenant sets Runtime.PodSpec. If a tenant instead sets only Runtime.Container and leaves Runtime.PodSpec nil — a perfectly ordinary way to configure an environment — MergePodSpec never runs, so the sanitizer that would have caught the dangerous securityContext never executes at all.
The result: a tenant holding nothing but the routine environments.fission.io create/update permission on their own Environment resource could set a securityContext with privileged: true, allowPrivilegeEscalation: true, or dangerous Linux capabilities on the runtime or builder container. The executor — running as its own high-privilege service account — then schedules that pod into the shared function or builder namespace exactly as specified. From there the chain is the standard one for any privileged-container escape: host filesystem access, host network access, and from a compromised node, a path toward compromising the rest of the cluster.
This wasn't an isolated slip. The same disclosure round included CVE-2026-50563 (the Container Executor path let a tenant's Function.spec.podspec merge straight into the executor-built Deployment), CVE-2026-50564 (the Environment CRD's podSpec fields propagated hostNetwork/hostPID/hostIPC/privileged/serviceAccountName with no filtering), and CVE-2026-50570 (a narrower capability bypass via CAP_SYS_TIME). Four related CVEs from one audit round is the signature of a systemic pattern — every code path that merges tenant input into a pod spec needs its own sanitizer, and it only takes one path someone forgot to wire up.
Why this keeps happening: RBAC was never the sandbox
The instinct to read into this bug is "Fission's RBAC was too permissive." That's the wrong lesson, and it's worth being precise about why.
RBAC answers exactly one question: is this identity authorized to perform this verb on this resource? environments.fission.io create/update was, correctly, a permission an ordinary tenant should hold — defining what your own function runs in is a core, expected capability of a serverless platform. RBAC did its job. The identity was authorized to create an Environment object, and it created one.
What RBAC cannot do — what no authorization layer can do — is inspect the runtime consequence of the object it just approved. Nothing in Kubernetes' RBAC model asks "and if this Environment gets merged into a pod spec, will the resulting container be privileged?" That question belongs to a completely different layer: admission control and validation logic that runs after authorization, inspecting the actual object being created. When that layer has a gap — as MergeContainer() did — RBAC has no way to compensate, because RBAC was never evaluating the thing that mattered.
This is the same distinction security researchers have been making about Kubernetes multi-tenancy generally: namespace scoping, RBAC, network policies, and resource quotas are four separate controls, and multi-tenancy is a property you construct by layering all four — miss one and you have the appearance of isolation, not the fact of it. Namespaces are a logical scoping mechanism, not a security boundary. RBAC is an authorization check sitting in front of whatever isolation the runtime actually provides — and if the runtime provides none beyond the standard container boundary, a single validation gap is the only thing standing between "authorized tenant" and "host compromise."
The container boundary itself is the deeper problem. Even with MergeContainer() fixed, a standard runc container sharing the host kernel is one unpatched kernel CVE away from the same outcome for a tenant sophisticated enough to find it. That's why the industry's answer to "untrusted code, shared node" has converged less on "audit every merge function" and more on "put a stronger isolation boundary under the pod than the kernel it shares with the host" — gVisor's user-space kernel intercepting syscalls before they reach the host, or Kata Containers' lightweight VM giving each pod its own guest kernel entirely. Neither approach makes a podspec-validation bug harmless by accident; both make it harmless by design, because the blast radius of a successful escape stops at a sandbox boundary instead of the host.
What this means for a platform scheduling tenant workloads on shared nodes
For any self-hosted PaaS running tenant code on Cluster-API-managed nodes shared across tenants — which is exactly the model a git-push deploy platform like Bex.co operates under — CVE-2026-50566 is a direct audit prompt, not just an interesting postmortem about someone else's code. Four things are worth checking against your own scheduling path:
- Stop treating "the tenant only has namespace-scoped RBAC" as a security claim about host access. It's a claim about who can create which objects, full stop. Whether that translates into "the tenant's code cannot reach the host" depends entirely on what happens to those objects afterward — and that logic lives in your controller/executor code, not in RBAC.
- Audit every code path that merges tenant-supplied fields into a pod spec, individually. Fission's round-4 hardening covered the
PodSpecmerge path and missed the standaloneContainermerge path. If your platform accepts tenant configuration through more than one field or API shape that eventually becomes part of a pod spec, each one needs its own validation — a sanitizer wired to only one of several merge functions is a sanitizer with a hole in it. - Enforce pod security at the admission layer, independent of application-level validation. A Pod Security Admission policy (or Kyverno/OPA Gatekeeper policy) that rejects
privileged: true,allowPrivilegeEscalation: true,hostNetwork,hostPID, or dangerous capabilities cluster-wide would have stopped this exploit even with theMergeContainer()bug fully intact — because it doesn't care which code path produced the pod spec, only what the spec says. - Run tenant workloads under a
RuntimeClasswith real kernel isolation — gVisor or Kata — rather than the default container runtime. This is the layer that makes the difference between "a validation bug is a critical incident" and "a validation bug is a bounded, sandboxed failure." "We audited the merge logic" is necessary. It is not sufficient, and CVE-2026-50566 is what "necessary but not sufficient" looks like when it fails.
None of this is a knock on Fission specifically — the team disclosed responsibly, shipped a fix in 1.24.0, and the round-4-then-round-5 pattern of hardening is exactly how mature open-source security response is supposed to look. The lesson generalizes past any one project: if your platform's answer to "why can't tenant A reach tenant B's node" is "because of RBAC," that's an incomplete answer. RBAC decides who gets to submit a workload. Isolation decides what that workload can do once it's running. A multi-tenant scheduler needs a real answer to both questions, and only one of them is enforced by the identity layer.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, scheduled on Cluster API-managed infrastructure. Star the repo on GitHub or deploy your first app today.
Sources
- CVE-2026-50566 — GitLab Advisory Database
- CVE-2026-50566 — Vulnerability-Lookup (CIRCL)
- Fission Critical Container Escape and Privilege Escalation (CVE-2026-50566) — TheHackerWire
- Fission, SecurityContext Bypass via Standalone Container Field, CVE-2026-50566 — DailyCVE
- Fission MessageQueueTrigger, Privilege Escalation, CVE-2026-50563 — DailyCVE
- Fission Environment CRD PodSpec Injection, CVE-2026-50564 — DailyCVE
- Fission Capability Bypass via CAP_SYS_TIME (CVE-2026-50570) — TheHackerWire
- Kata, gVisor, or Firecracker? Container Isolation Guide — Edera
- Three multi-tenant isolation boundaries of Kubernetes — Sysdig
- Kubernetes Multi-tenancy and RBAC — vCluster
- Fission — Open Source Kubernetes-native Serverless Framework



