CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Dashboard
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-22728
4.90.04%

The Old Switcheroo: Unsealing Secrets via Metadata Manipulation in Bitnami Sealed Secrets

Alon Barad
Alon Barad
Software Engineer

Feb 26, 2026·6 min read·11 visits

PoC Available

Executive Summary (TL;DR)

A logic flaw in the `/v1/rotate` endpoint allows attackers to bypass scope restrictions. By modifying the metadata of a SealedSecret during rotation, an attacker can force the controller to re-encrypt a restricted secret as 'cluster-wide,' enabling them to decrypt it in any namespace.

Bitnami Sealed Secrets, the standard-bearer for GitOps secret management, contains a logic flaw in its key rotation mechanism that allows attackers to widen the scope of encrypted secrets. By injecting malicious metadata during the rotation process, an attacker can transform a strictly scoped secret (bound to a specific namespace) into a cluster-wide secret, subsequently recovering the plaintext credentials. This vulnerability highlights a classic 'Time-of-Check to Time-of-Use' (TOCTOU) style disconnect between the decryption and re-encryption phases.

The Hook: Pandora's Box for GitOps

In the world of Kubernetes GitOps, managing secrets is a headache. You can't commit raw YAMLs to GitHub unless you want to end up on a security researcher's 'Wall of Sheep'. Enter Bitnami Sealed Secrets. It uses asymmetric cryptography to turn your sensitive Secret objects into SealedSecret objects—inert, encrypted blobs that are safe to commit to public repositories. The cluster-side controller holds the private key to decrypt them.

But crypto systems eventually need to rotate keys. Whether it's for hygiene or because an admin leaked a private key on Slack, the sealed-secrets-controller offers a /v1/rotate endpoint. You give it a SealedSecret encrypted with an old key, and it hands you back a SealedSecret encrypted with the new key.

This sounds mundane, but in security, the transition points—where data changes state—are where the bodies are buried. CVE-2026-22728 is a perfect example of what happens when a system validates inputs correctly but fails to carry that validation through to the output.

The Flaw: Trusting the Wrapper

To understand the bug, you have to understand the anatomy of a SealedSecret. It's essentially a wrapper. The outer object contains metadata (Name, Namespace), and the spec.encryptedData contains the ciphertext. Crucially, the ciphertext is generated based on a 'Scope'.

Scopes dictate who can decrypt the secret:

  • Strict: Only the specific Name and Namespace can decrypt.
  • Namespace-wide: Anyone in the Namespace can decrypt.
  • Cluster-wide: Anyone in the Cluster can decrypt.

The controller enforces this during decryption. If you try to decrypt a Strict secret in the wrong namespace, the crypto math fails. However, the Rotate function performs a two-step dance: Decrypt (Unseal) then Re-encrypt (Seal).

The vulnerability lies in the gap between these steps. The controller would successfully decrypt the incoming secret using the valid outer metadata and signature. But when it came time to re-encrypt it for the output, it didn't use the trusted properties it just verified. Instead, it looked at the spec.template.metadata—a field inside the object that the user controls and which is effectively just a blueprint for the final Kubernetes Secret. By manipulating this template before sending it to the rotation endpoint, an attacker can trick the controller into re-sealing the secret with a much wider scope than intended.

The Code: The Smoking Gun

Let's look at the Go code responsible for this mix-up. In the vulnerable versions (pre-0.36.0), the Rotate function was too trusting. It took the SealedSecret object, unsealed it to get the plaintext, and then immediately passed that plaintext back into NewSealedSecret to generate the new blob.

The problem? It used the spec.template directly from the input to define the new secret's metadata. Here is the logic flaw in concept:

// VULNERABLE LOGIC (Conceptual)
func Rotate(input SealedSecret) {
  // Step 1: Decrypt using Outer Metadata (Verified)
  plaintext, err := Unseal(input)
  
  // Step 2: Re-encrypt using Inner Template (UNVERIFIED)
  // The attacker changed input.Spec.Template to be ClusterWide!
  newSealedSecret := Seal(plaintext, input.Spec.Template)
  return newSealedSecret
}

The fix, applied in version 0.36.0, forces the application to synchronize its state. It explicitly copies the trusted outer metadata (which was necessary for the successful decryption) into the inner template before re-sealing. This ensures the input scope matches the output scope.

// PATCHED LOGIC
// File: pkg/controller/controller.go
 
if !reflect.DeepEqual(s.ObjectMeta, s.Spec.Template.ObjectMeta) {
    // FORCE the trusted metadata onto the template
    s.ObjectMeta.DeepCopyInto(&s.Spec.Template.ObjectMeta)
    slog.Warn("Sealed Secret metadata doesn't match... fixed it for you.")
}
secret, err := c.attemptUnseal(s)

It's a classic "check your inputs" fix, but applied to the internal state transfer of the application.

The Exploit: The Kansas City Shuffle

An attacker with access to the /v1/rotate endpoint (which typically requires high privileges, hence the CVSS 4.9, but bear with me) can pull off a neat trick. Let's say there is a super sensitive secret db-root-pass that is Strictly scoped to the prod namespace. You, the attacker, want to read it, but you only have access to the dev namespace.

Step 1: Capture the Blob You grab the SealedSecret YAML for db-root-pass from the public Git repo.

Step 2: Modify the Blueprint You edit the YAML locally. You leave the encryptedData alone (touching it would break decryption). Instead, you add an annotation to the template:

spec:
  template:
    metadata:
      annotations:
        sealedsecrets.bitnami.com/cluster-wide: "true"

Step 3: The Rotation Request You send this modified object to the controller's rotate endpoint. The controller sees the valid encryptedData and valid outer metadata. It decrypts the secret successfully.

Step 4: The Turn The controller now needs to encrypt this plaintext with the new key. It looks at your injected annotation: "Oh, the user wants this to be Cluster Wide? Sure thing." It generates a new blob that can be decrypted anywhere.

Step 5: The Prestige You take the response (the new SealedSecret), apply it to your dev namespace, and since it is now Cluster Wide, the controller happily decrypts it for you. You now have the production database password.

The Impact: Why the Low Score?

You might be wondering: "If I can steal production secrets, why is the CVSS score only 4.9?" That feels low for a confidentiality breach of this magnitude.

The devil is in the Privileges Required (PR:H) metric. To communicate with the /v1/rotate endpoint, you usually need permission to POST to the controller's API. In many clusters, this endpoint isn't exposed to the world; it's internal or restricted to admins. If you are already a Cluster Admin, you don't need this exploit—you can just read the secrets directly from etcd.

However, this vulnerability becomes critical in multi-tenant environments with loose RBAC or specific delegation models. If developers are allowed to trigger rotations (perhaps to handle key expiry) but aren't supposed to read other teams' secrets, this is a direct privilege escalation path. It transforms a maintenance function into a data exfiltration tool. It also serves as a warning for anyone building operators: never trust metadata embedded inside a payload if you have a verified source of truth available externally.

Official Patches

BitnamiOfficial Release Notes for v0.36.0

Fix Analysis (1)

Technical Appendix

CVSS Score
4.9/ 10
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N
EPSS Probability
0.04%
Top 89% most exploited

Affected Systems

Bitnami Sealed Secrets Controller < 0.36.0

Affected Versions Detail

Product
Affected Versions
Fixed Version
sealed-secrets
Bitnami
< 0.36.00.36.0
AttributeDetail
CWE IDCWE-668
Attack VectorNetwork
CVSS4.9 (Medium)
Privileges RequiredHigh
ImpactConfidentiality Loss
Exploit StatusPoC Available

MITRE ATT&CK Mapping

T1528Steal Application Access Token
Credential Access
T1098Account Manipulation
Persistence
CWE-668
Exposure of Resource to Wrong Sphere

Known Exploits & Detection

GitHub (Unit Tests)The regression test `TestRotateKeepScope` effectively acts as the PoC for this vulnerability.

Vulnerability Timeline

Validation logic added to codebase
2026-02-24
DeepCopyInto fix finalized
2026-02-25
CVE and GHSA Published
2026-02-26

References & Sources

  • [1]GHSA-465p-v42x-3fmj Advisory
  • [2]NVD Entry for CVE-2026-22728