Helm Chart Security Reference
Helm adds a templating layer; most K8s rule failures are invisible until the chart is rendered. Always scan rendered output and raw templates.
Scan Approaches
1. Render, then scan (highest fidelity)
helm template my-release ./my-chart > rendered.yaml
checkov -f rendered.yaml --framework kubernetes
kubesec scan rendered.yaml
# With production values
helm template my-release ./my-chart -f values-prod.yaml > rendered-prod.yaml
checkov -f rendered-prod.yaml --framework kubernetesRender with EVERY values profile that ships (dev / staging / prod). A chart that's safe on defaults can ship a 0.0.0.0/0 LoadBalancer under a non-default values file.
2. Direct chart scan
checkov -d ./my-chart --framework helm
checkov -d ./my-chart --framework helm --var-file values-prod.yaml
trivy config ./my-chartDirect scanning catches template issues Checkov understands natively, but will miss rules that depend on fully-resolved values.
3. Helm unit tests + policy gate
helm plugin install https://github.com/helm-unittest/helm-unittest
helm unittest ./my-chart
# Combined with conftest
helm template ./my-chart | conftest test - -p policy/Chart.yaml Security
-
appVersionpinned to specific version (no floating tags) -
dependencies[].repositoryfrom trusted, HTTPS repos -
dependencies[].versionpinned (exact, not^/~where possible) -
kubeVersionconstraints set (avoid running on unsupported clusters) - No deprecated API versions in templates (
kubectl-deprecations,pluto) - Chart provenance (
helm package --sign, verify with--verify)
values.yaml Security
- No secrets in default
values.yaml(useexistingSecretpatterns) - Security-sensitive defaults fail-closed (e.g.
networkPolicy.enabled: true) - Image tags in values are pinned digests where possible
-
serviceAccount.create: truewith minimal permissions
Common Helm Pitfalls
- Conditional security contexts:
securityContextunder{{- if .Values.securityContext }}→ root-running pods if value omitted. - Unquoted tags:
image: myimg:{{ .Values.tag }}wheretag: 1.0renders as float in some cases. tplrendering of user input: possible SSTI if chart ingests untrusted values.lookupfunction in charts: requires cluster access; can leak state across render environments.
Using pluto for deprecated APIs
pluto detect-helm -o wide
pluto detect-files -d ./my-chart/templates