Pepr's Open Door: The Perils of Default 'Admin' Mode
Jan 16, 2026·5 min read
Executive Summary (TL;DR)
Pepr, a TypeScript framework for Kubernetes, essentially gives root privileges (`cluster-admin`) to any module created with its default settings. If an attacker compromises a Pepr module—perhaps through a dependency vulnerability or bad custom code—they inherit full control over the entire cluster. The fix? A console warning telling you not to do that in production.
The Pepr Kubernetes framework defaults to generating 'cluster-admin' RBAC permissions for new modules, turning a simple development convenience into a potential production nightmare.
The Hook: Kubernetes Magic, Made Too Easy
We all hate writing Kubernetes YAML. It’s verbose, error-prone, and debugging it feels like staring into the abyss. Enter Pepr: a sleek, TypeScript-based framework that promises to handle K8s mutations and orchestration without the headache. It’s the kind of tool developers love because it reduces friction. You run npx pepr init, write some TypeScript, and boom—your cluster is doing magic.
But here is the thing about friction in security: sometimes it exists for a reason. Friction slows you down enough to notice you are about to hand the keys to the castle to a hello-world script. Pepr decided that configuring RBAC (Role-Based Access Control) was too much friction for the "Day 1" experience. So, they removed it entirely.
Instead of asking what permissions your module needs, Pepr's default behavior was to shrug and say, "Just take everything." It is the digital equivalent of a hotel giving the master key to every guest because asking which room number they booked is too much administrative overhead.
The Flaw: The Road to Hell is Paved with Defaults
The vulnerability (GHSA-w54x-r83c-x79q) isn't a buffer overflow or a deserialization bug. It’s a philosophical failure in the "Secure by Default" doctrine. When a developer runs the initialization command to scaffold a new project, Pepr generates the Kubernetes manifests required to deploy that module. One of those manifests is a ClusterRole.
In the vulnerable versions (everything prior to 1.0.5), the generation logic defaulted the RBAC mode to "admin". In the world of Pepr, "admin" is code for cluster-admin. This means the ServiceAccount attached to your pod gets wildcard permissions (*) on wildcard resources (*) across all API groups (*).
This creates a massive dormant risk. Developers often assume frameworks handle best practices for them. A developer might write a benign module that just labels pods, deploy it to production, and never look at the generated rbac.yaml. Unknowingly, they have deployed a pod with God-mode privileges sitting right next to their web apps.
The Code: The Smoking Gun
Let’s look at the source code responsible for this generosity. The file src/lib/assets/rbac.ts contains a function clusterRole responsible for synthesizing the YAML. Notice the function signature and the ternary operator in the return statement.
export function clusterRole(
name: string,
capabilities: CapabilityExport[],
rbacMode: string = "admin", // <--- The culprit
customRbac: PolicyRule[] | undefined,
): kind.ClusterRole {
// [omitted logic for scoped rules]
return {
apiVersion: "rbac.authorization.k8s.io/v1",
kind: "ClusterRole",
metadata: { name },
rules:
rbacMode === "scoped"
? deduplicatedRules
: [
{ // The "Admin" Mode
apiGroups: ["*"],
resources: ["*"],
verbs: ["create", "delete", "get", "list", "patch", "update", "watch"],
},
],
};
}The code is brutally simple. If rbacMode isn't explicitly set to scoped, it defaults to the array containing the wildcard rule. There is no middle ground, no "read-only" default. It is all or nothing, and the default is "all".
The Exploit: From RCE to Cluster Takeover
How do we weaponize this? This is a post-compromise privilege escalation vector. The vulnerability itself doesn't let us break in, but it ensures that if we do break in, we win the game immediately. Imagine a scenario where a developer imports a vulnerable npm package into their Pepr module (a common occurrence in the Node.js ecosystem) or writes a custom capability with an improperly sanitized input.
Step 1: The Foothold.
The attacker exploits an RCE vulnerability in the Pepr module's custom logic. They now have a shell inside the pepr-system pod.
Step 2: Credential Harvesting.
Standard Kubernetes pods mount a ServiceAccount token at /var/run/secrets/kubernetes.io/serviceaccount/token. The attacker reads this token.
Step 3: The Pivot.
Because of the vulnerable default ClusterRole, this token has cluster-admin rights. The attacker configures kubectl (or uses curl) to talk to the K8s API server using this token.
[!NOTE] At this point, the concept of "Namespaces" effectively ceases to exist for the attacker. They can delete the
loggingnamespace to blind the defenders, dump secrets from thekube-systemnamespace, or deploy a DaemonSet of crypto miners on every node.
This transforms a low-severity application bug into a critical infrastructure compromise.
The Fix: A Warning Label on the Chainsaw
The remediation chosen by the maintainers in version 1.0.5 is... pragmatic, if slightly disappointing for purists. They did not change the default behavior to scoped. Changing the default would break the "frictionless" experience for new users who just want the demo to work without debugging RBAC errors.
Instead, they opted for Security by Verbosity. The patch (Commit d4675a6) adds a bright yellow warning to the CLI output during initialization.
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.`
);They essentially put a "Caution: Hot Surface" sticker on the nuclear reactor. It relies entirely on the developer actually reading the standard output logs during their build process—something we all know developers definitely do with 100% consistency. If you are auditing a Pepr setup, do not assume the version upgrade fixed the issue. The vulnerability is the configuration, not the binary.
Official Patches
Fix Analysis (1)
Technical Appendix
CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:UAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
pepr defenseunicorns | < 1.0.5 | 1.0.5 |
| Attribute | Detail |
|---|---|
| CWE | CWE-276 (Incorrect Default Permissions) |
| CVSS v4.0 | 1.7 (Low) |
| Real-World Impact | Critical (Cluster Compromise) |
| Attack Vector | Adjacent / Network (Post-Compromise) |
| Affected Versions | < 1.0.5 |
| Exploit Status | Config-based (Trivial) |
MITRE ATT&CK Mapping
The product creates a default configuration file with permissions that are broader than necessary, exposing the system to unintended access or modification.
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.