Feb 18, 2026·5 min read·2 visits
Pepr, a Kubernetes middleware framework, defaulted to granting `cluster-admin` privileges to its modules prior to version 1.0.5. This means any code running in a Pepr module—including third-party dependencies—had full control over the cluster by default. The fix is largely advisory, adding warnings rather than enforcing restrictions.
In the race to improve Developer Experience (DX), security often gets left in the dust. This is the story of CVE-2026-23634, where the Pepr Kubernetes framework decided the best way to help you get started was to silently grant your code absolute power over the entire cluster. It's a classic case of 'secure defaults' being sacrificed on the altar of 'it just works'.
In the world of Kubernetes, the cluster-admin role is the Holy Grail. It is the root user, the master key, the one ring to rule them all. If you have it, you can read every secret, delete every namespace, and essentially hold the entire infrastructure hostage. Security 101 dictates that you never give this permission out unless absolutely necessary, and certainly not by default.
Then came Pepr. Pepr is a slick TypeScript framework designed to make Kubernetes middleware easy. Instead of writing complex controllers in Go, you write simple TS modules to mutate resources. It’s elegant, it’s modern, and prior to version 1.0.5, it was incredibly dangerous.
To ensure a "frictionless" onboarding experience, Pepr decided that the path of least resistance was the path of most privilege. When a developer initialized a new module, the framework automatically generated RBAC manifests binding that module's ServiceAccount to cluster-admin. No questions asked, no warnings given. You wanted to write a simple label mutator? Congratulations, you just deployed a pod with the ability to nuke the cluster.
The root cause here isn't a buffer overflow or a logic error in a parser. It's a philosophical failure. The vulnerability (CWE-272) is a violation of the Principle of Least Privilege (PoLP). The developers prioritized the "getting started" experience over security boundaries.
Under the hood, when you ran npx pepr init, the CLI generated a ClusterRoleBinding. In a secure world, this binding would be scoped—perhaps allowing the module to watch Pods and patch them, and nothing else. In Pepr's world, it effectively generated this:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: pepr-system-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin # <--- The keys to the kingdom
subjects:
- kind: ServiceAccount
name: pepr-system
namespace: pepr-systemThis is the configuration equivalent of leaving your front door unlockable because keys are "too hard" for new homeowners to understand. While the CVSS score is technically 0.0 (because the vendor argues this is a configuration choice), the actual risk in a production environment is Critical.
The remediation for this CVE is fascinating because it doesn't actually stop you from shooting yourself in the foot; it just puts a warning label on the gun. The maintainers decided that breaking backward compatibility or forcing users to understand RBAC immediately was too high a cost.
Here is the essence of the patch in commit d4675a662b8602fcde7e4bf603432f2f133b1fd1. They didn't remove the admin capability; they just added a Log.warn.
Before (v1.0.4): The CLI would silently generate the admin binding. Silence is consent.
After (v1.0.5):
// src/lib/assets/rbac.ts
if (config.rbacMode === 'admin') {
Log.warn(
`The default RBAC mode (admin) generates a ClusterRole with cluster-admin level ` +
`permissions for the hello-pepr capability. This is intended for demo/POC purposes only ` +
`and should NOT be used in production.`
);
// Proceed to generate the admin binding anyway...
}While they also hardened documentation to strongly suggest using --rbac-mode=scoped, the default behavior arguably remains a trap for the unwary. It relies on developers actually reading their terminal output during initialization—a bold assumption in the age of npm install && go grab coffee.
Since this is a privilege escalation primitive, let's look at how an attacker exploits it. The vector here is likely Supply Chain Compromise. Pepr modules are just Node.js projects. They pull in dependencies from npm.
Imagine a developer creates a Pepr module to enforce some naming conventions. They install a helper library: npm install color-string. Unknown to them, color-string has been typo-squatted or hijacked.
Because the Pepr module runs as cluster-admin, that malicious npm package inherits those permissions immediately upon startup. It doesn't need a kernel exploit or a container escape. It just needs to make one HTTP request.
The malicious code simply reads the token mounted at /var/run/secrets/kubernetes.io/serviceaccount/token and sends it to an external server. The attacker now has a persistent, valid cluster-admin token. They can deploy crypto miners, steal database credentials, or ransom the entire cluster.
Since the software doesn't force your hand, you have to be the adult in the room. The fix involves both upgrading and changing your workflow.
First, upgrade to Pepr v1.0.5+. This ensures you at least get the warnings and the documentation references. Second, stop using defaults. When you initialize or build a module intended for anywhere near a production cluster, you must explicitly scope the RBAC.
The Command You Should Be Running:
npx pepr build --rbac-mode=scopedThis forces Pepr to generate a Role that only includes the permissions you explicitly defined in your capabilities. If your module only needs to read ConfigMaps, that's all it gets.
Finally, audit your cluster. Run the following command to see if you've already fallen into the trap:
kubectl get clusterrolebindings -o json | jq '.items[] | select(.roleRef.name=="cluster-admin") | .metadata.name'If you see pepr-system or similar auto-generated names in that list, you have some urgent refactoring to do.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Pepr Defense Unicorns | < 1.0.5 | 1.0.5 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-272 (Least Privilege Violation) |
| CVSS Score | 0.0 (Functional Critical) |
| Attack Vector | Configuration / Supply Chain |
| Privileges Required | None (if supply chain compromised) |
| Impact | Full Cluster Compromise |
| Fix Type | Advisory / Warning |
The software does not perform a privilege check or uses a default setting that grants excessive privileges.