KSECRETS picoCTF 2026 Solution

Published: March 20, 2026

Description

We have a kubernetes cluster setup and the flag is in the secrets. You think you can get it?

Launch the challenge instance and SSH in.

A kubeconfig or service account token will be available in the environment.

  1. Step 1Check the Kubernetes context
    Verify kubectl works and read kubectl auth can-i --list carefully: you want get or list on the secrets resource. create or patch without get is read-blind (you can write but not read), which is a different game.
    bash
    kubectl config current-context
    bash
    kubectl get namespaces
    bash
    kubectl auth can-i --list
    bash
    kubectl auth can-i get secrets
    bash
    kubectl auth can-i list secrets
    Learn more

    Kubernetes (k8s) is an open-source container orchestration platform. It organises containerised workloads into pods (groups of containers), and groups pods into namespaces (logical isolation boundaries). kubectl is the command-line client that communicates with the Kubernetes API server.

    A kubeconfig file (typically at ~/.kube/config) stores cluster connection details, credentials, and the current context (which cluster and namespace you are targeting). The kubectl config current-context command shows which context is active. kubectl auth can-i --list shows all actions the current user is permitted to perform - this is the first step in Kubernetes privilege assessment during a penetration test.

    In cloud environments, Kubernetes clusters are commonly managed by cloud providers (Amazon EKS, Google GKE, Azure AKS). Each pod can be assigned a service account with associated permissions. When a pod is compromised, attackers often find the service account token at /var/run/secrets/kubernetes.io/serviceaccount/token and use it to authenticate to the API server.

  2. Step 2List Kubernetes secrets
    Run kubectl get secrets first to see the names. If the flag-bearing secret isn't obvious from the name, dump every secret as YAML and grep for the picoCTF prefix in the base64-decoded data.
    bash
    kubectl get secrets
    bash
    kubectl get secrets --all-namespaces
    bash
    # If the relevant secret isn't obviously named, search every value:
    bash
    kubectl get secrets -o yaml | grep -i flag
    bash
    # Or decode every value to find the one that starts with picoCTF{:
    bash
    kubectl get secrets -o jsonpath='{range .items[*]}{.metadata.name}{": "}{range .data.*}{@}{"\n"}{end}{end}' | while read line; do echo "$line"; done
    Learn more

    Kubernetes Secrets are API objects designed to store sensitive data like passwords, tokens, and certificates. They are stored in etcd(the cluster's distributed key-value store) and can be mounted into pods as files or exposed as environment variables. The built-in Secrets object provides namespacing and RBAC-controlled access, but it does not provide encryption by default - values are stored base64-encoded, not encrypted.

    The key Kubernetes RBAC permission for this challenge is get and list on the secrets resource. A cluster that grants broad secret-read permissions to any service account is a common misconfiguration. Real-world Kubernetes security incidents like the Tesla cryptojacking breach (2018) and several CI/CD supply chain attacks exploited overly permissive service account tokens to exfiltrate secrets.

    Kubernetes also supports integration with external secret management systems like HashiCorp Vault (via the Vault Agent Injector or CSI Driver), AWS Secrets Manager (via the External Secrets Operator), and Sealed Secrets (which encrypts secrets as SealedSecret CRDs that are safe to commit to git). These provide encryption at rest and fine-grained access control beyond what native Kubernetes Secrets offer. See the Linux CLI guide for more on enumerating cluster state from the command line.

  3. Step 3Retrieve the flag secret
    Describe or get the flag secret and decode the base64-encoded value.
    bash
    kubectl get secret flag-secret -o yaml
    bash
    kubectl get secret flag-secret -o jsonpath='{.data.flag}' | base64 -d
    Learn more

    Kubernetes Secret values are stored base64-encoded in etcd and in the YAML output of kubectl get secret. This encoding is not encryption - it is purely to allow arbitrary binary data to be stored in the YAML format. Anyone with read access to the secret can trivially decode the value with base64 -d. This is why access control on the secrets resource is critical.

    The -o jsonpath flag applies a JSONPath expression to the API response and extracts just the requested field. {.data.flag} navigates to the data map and then the flag key. Piping through base64 -d decodes the value in one command. The equivalent using jq is kubectl get secret flag-secret -o json | jq -r '.data.flag' | base64 -d.

    Encryption at rest for Kubernetes Secrets requires configuring the API server with an EncryptionConfiguration that specifies an encryption provider (AES-GCM, AES-CBC, or a KMS provider backed by an external key management system). Without this configuration, secrets in etcd are only base64-encoded and readable by anyone with direct etcd access. Most managed Kubernetes services (EKS, GKE) enable encryption at rest by default; self-managed clusters must configure it explicitly.

Flag

picoCTF{k8s_s3cr3ts_...}

Kubernetes secrets are stored base64-encoded; kubectl get secret with -o jsonpath decodes them.

Want more picoCTF 2026 writeups?

Useful tools for General Skills

Related reading

What to try next