# Leaked Kubernetes Secret? Rotate Its Values

> Kubernetes Secret manifest exposed with real values? Rotate each credential at its source, update the cluster, then check who could read the Secret.

Source: https://leakwatch.net/secrets/kubernetes-secret-yaml

---

[LeakWatch](/)

[Product](/product)[Live feed](/leaks)[Guides](/secrets)[Blog](/blog)[Free scan](/)

1.  [Home](/)
2.  [Secrets](/secrets)
3.  Kubernetes Secret YAML

Cloud · Secret guide

# Leaked Kubernetes Secret YAML: what to do in the first hour

Critical severityDetected onlyLast verified October 23, 2026 · 5 min read

A Kubernetes Secret stores the values your workloads read at runtime: database passwords, API keys, TLS private keys and registry credentials. Anyone who reads the manifest or the Secret object gets those values, and the file format does not protect them, because the values are only encoded. Rotate every value the Secret held, not just the file, since the manifest is the copy you can see and the cluster may hold others.

[Check your GitHub account for leaked secrets — free](/)

Provider

Other

Severity

Critical

Impact

Cloud infrastructure access

Checked live by LeakWatch

No

## What a Kubernetes Secret YAML looks like

A Secret manifest is a YAML file with `kind: Secret` near the top and a `data` block below it. Each entry in `data` is a name followed by an encoded value:

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: app-credentials
type: Opaque
data:
  password: …XXXX
```

The values are base64 strings. Base64 is an encoding, not encryption, so anyone who has the string has the secret. A manifest that uses `stringData` instead holds the values in plain text, and the cluster encodes them when it stores the object. Either way, `kubectl get secret -o yaml` prints the same encoded values, so a leaked kubeconfig with read access to Secrets exposes them too. The `kind: Secret` line and the `data` block together are what identify the file. A base64 string on its own says nothing.

## How Kubernetes Secret YAML files get leaked

-   **Manifests committed with values filled in.** A Secret written by hand and saved in the repository, instead of being generated at deploy time.
-   **Helm values and Kustomize overlays.** Real passwords stored in values files next to the templates.
-   **Debug output.** A `kubectl get secret -o yaml` result pasted into an issue, a chat thread or a ticket to troubleshoot a deployment.
-   **Namespace backups.** Exports saved to a shared drive or to a storage bucket with open access.
-   **Broad kubeconfig files.** Configuration with wide read rights copied onto laptops and CI runners, which lets whoever holds it read every Secret in scope.

## What to do in the first hour

1.  **Identify the Secret.** Read the `name` and `namespace` in the manifest, then check which workloads mount it or read its values. Only then do you know which systems need new credentials.
2.  **Rotate the credentials at their source first.** A new value in the cluster does nothing if the old password still works in the database or the old key still works at the vendor. Create the new credential where the value belongs.
3.  **Update the Secret in the cluster.** Apply the new value through your deployment tool, not with a command that leaves the value in shell history. Pods that read the value as environment variables must be restarted. Mounted files update on their own, but confirm that in your setup.
4.  **Remove the old value from the source.** Delete the file with real values or replace them with placeholders, and stop committing generated manifests.
5.  **Check who read it.** If your cluster has audit logging, search for `get` and `list` requests against Secrets in that namespace during the exposure window. Without audit logs, assume the values were read.
6.  **Review access.** Check which service accounts and users can read Secrets in that namespace, and remove rights they do not need.
7.  **Clean the repository.** See [I accidentally pushed an API key to GitHub](/blog/i-accidentally-pushed-an-api-key-to-github) for the history rewrite steps, and [deep scan your whole git history](/blog/deep-scan-your-whole-git-history) to find older copies.

Not sure what else leaked? [Run a free scan](/).

[Not sure what else leaked? Run a free scan.](/)

## Revoke it at Kubernetes

Kubernetes has no single key to revoke. The fix is to rotate each value in the Secret and to rotate the credential behind it at its own provider. Start from the list of keys in the manifest and follow each one to its source, such as the database, the cloud account, or the vendor’s API keys page. Once the old credential is disabled, the value in the leaked file is worthless. Keep the old Secret only until the new one is confirmed in production, then delete it.

## How LeakWatch detects it

The rule is called Kubernetes Secret YAML. It looks for a `kind: Secret` line and, within a couple of hundred characters, a `data:` block whose entry holds a base64-looking value of at least ten characters, an empty value, or a template placeholder. The order can be reversed, with the `data:` block first and `kind: Secret` after it. Matching is not case-sensitive. Plain manifests without a Secret kind, and Secrets whose data entries are too short to look like encoded values, are not reported. The severity is **critical**. This type is not checked live: LeakWatch does not contact your cluster or any provider with the values it finds.

LeakWatch detects this format but does **not** check it live: it can tell you the key is exposed, not whether it still works. Assume it does until you have revoked it.

## FAQ

Is a base64 Secret value encrypted?

No. Base64 is a reversible text encoding. Unless your cluster enables encryption at rest for Secrets, the values are stored in a form that anyone with API access can read, and a leaked manifest gives them away at once.

If I delete the Secret object, is the leak fixed?

No. Deleting it stops workloads from getting new values, but the value in the leaked file still works until you rotate it at its source. Deletion is part of the cleanup, not the fix.

Do I have to rotate everything in the namespace?

Rotate every value that was in the leaked Secret. If you cannot tell whether other Secrets in the same namespace were read, rotate those too.

## Related

-   [Database Connection String](/secrets/database-connection-string)
-   [Vault Service Token](/secrets/vault-service-token)
-   [GCP Service Account Key](/secrets/gcp-service-account-key)
-   [I accidentally pushed an API key to GitHub](/blog/i-accidentally-pushed-an-api-key-to-github)
-   [Which vendors leak most this week](/leaks/trends)
-   [All secret guides](/secrets)

[Get alerted next time a secret leaks — create a free account](/)

LeakWatch is not affiliated with Other.

![Gabriel Diyan, founder of LeakWatch](/brand/Photo-Gabriel-Diyan.webp)

Gabriel Diyan (0xCr0c0)

Cybersecurity student, founder of LeakWatch. I built and run the scanner described here — the detection patterns, the false-positive classifier and the provider validators are mine. [More about who I am](/about).

[GitHub](https://github.com/Leakwatch-Scan) · [X](https://x.com/LeakwatchScan) · [LinkedIn](https://www.linkedin.com/in/gabriel-diyan-80a378375) · [GitHub (personal)](https://github.com/crocogab)

LeakWatch

Secrets leak into public commits every minute. This watches the forges for yours. Built and run by [Gabriel Diyan](/about), a cybersecurity student — [why LeakWatch exists](/about).

Scan

-   [Product](/product)
-   [Live feed](/leaks)
-   [Trends](/leaks/trends)
-   [API docs](/docs)
-   [CI/CD](/docs?tab=ci)

Read

-   [Blog](/blog)
-   [Secret guides](/secrets)
-   [Changelog](/changelog)
-   [About](/about)

Verify

-   [Security](/security)
-   [Privacy](/privacy)
-   [Terms](/terms)
-   [Legal](/legal)
-   [Contact](/contact)
-   [Status](https://status.leakwatch.net)

© 2026 LeakWatch

[GitHub](https://github.com/Leakwatch-Scan)[X](https://x.com/LeakwatchScan)
