[Bug] Empty arrays bypass pattern-based validation — Enforce policies silently pass
Kyverno Version
1.16.4
Kubernetes Version
1.28.x
Kubernetes Platform
EKS
Kyverno Rule Type
Validate
Description
When a resource field is an empty array, Kyverno's pattern validation treats the pattern as satisfied without ever checking it. This applies both to scalar patterns (replicas: 3 vs replicas: []) and to object patterns inside arrays (containers: [{securityContext: {runAsNonRoot: true}}] vs containers: []). An Enforce validation rule intended to require a value is silently satisfied by an empty array — an enforcement bypass for any field that can legitimately be empty (initContainers, volumes, env, args, imagePullSecrets, or any unconstrained CRD field).
This is inconsistent with a missing field: a non-optional pattern key that is absent fails validation, but the same key set to [] passes.
Root cause: pkg/engine/validate/validate.go — validateResourceElement and validateArray / validateArrayOfMaps.
- Scalar pattern vs array resource: the elementary-values branch (
case string, float64, int, int64, bool, nil, lines 92–107) ranges over the resource array and returnsnilif the loop never runs. - Object pattern vs empty resource array:
validateArray(line 205) dispatches tovalidateArrayOfMaps(lines 260–288), which likewise iterates zero times and returns"" , nil(pass).
Execution path: MatchPattern → validateResourceElement → for _, res := range resource { ... } / for i, resourceElement := range resourceMapArray → empty loop → return "", nil → RulePass.
Verified behavior (engine-level, via MatchPattern):
scalar pattern vs empty array: err=<nil> → PASS
map pattern vs empty array: err=<nil> → PASS
scalar pattern vs non-empty mismatch: err=... → FAIL
missing (omitted) field vs map pattern: → FAILActual behavior
The engine records Pass; the intended requirement is silently unenforced whenever the empty array is present on the object the engine sees.
Additional context
- Existing tests never exercise the empty-array case:
validate_test.goarray cases (TestValidateMap_*,TestValidateMapElement_*) all use non-empty arrays. - Suggested fix: in the elementary-values
[]interface{}resource branch ofvalidateResourceElement, return an error whenlen(resource) == 0(or only pass for wildcard patterns); likewise treat an empty resource array as a pattern failure invalidateArrayOfMapswhen the pattern is not purely anchor-based. - Suggested regression test:
TestValidateMap_EmptyArrayFailswith the pattern/resource above, assertingMatchPatternreturns an error.
Steps to reproduce
Steps to reproduce
Use kyverno apply (or a unit test calling MatchPattern). Do not rely on kubectl apply of a native Pod: the API server typically omits empty slices (json:",omitempty"), so initContainers: [] becomes a missing field and the pattern fails (blocked) instead of bypassing. The bypass is the empty-array case the engine actually sees.
- Save the policy and resource below.
- Run
kyverno apply policy.yaml --resource pod.yaml. - Observe that the resource passes even though the rule requires every initContainer to set
runAsNonRoot: true.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-initcontainer-nonroot
spec:
validationFailureAction: Enforce
rules:
- name: initcontainers-nonroot
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Every initContainer must set runAsNonRoot: true"
pattern:
spec:
initContainers:
- securityContext:
runAsNonRoot: trueapiVersion: v1
kind: Pod
metadata:
name: demo
spec:
initContainers: [] # empty array — bypasses the pattern in the engine
containers:
- name: app
image: nginxThe same bypass applies to scalar patterns on CRDs with a permissive/absent schema, e.g. pattern spec.replicas: 3 vs. a resource with spec.replicas: [] (MatchPattern returns no error). Native Kubernetes integer fields like Deployment spec.replicas reject [] at schema validation, so that variant is CRD-only.
Expected behavior
Expected behavior
An empty array must not satisfy a pattern that requires elements with specific properties, and must not satisfy a scalar value pattern. The rule should record a failure and block admission under Enforce.
Screenshots
No response
Kyverno logs
$ kyverno apply policy.yaml --resource pod.yaml --table --detailed-results --remove-color
Applying 3 policy rule(s) to 1 resource(s)...
│────│───────────────────────────────│────────────────────────│──────────────────│────────│────────│──────────────────────────────────────────────────│
│ ID │ POLICY │ RULE │ RESOURCE │ RESULT │ REASON │ MESSAGE │
│────│───────────────────────────────│────────────────────────│──────────────────│────────│────────│──────────────────────────────────────────────────│
│ 1 │ require-initcontainer-nonroot │ initcontainers-nonroot │ default/Pod/demo │ Pass │ │ validation rule 'initcontainers-nonroot' passed. │
│────│───────────────────────────────│────────────────────────│──────────────────│────────│────────│──────────────────────────────────────────────────│Slack discussion
No response
Troubleshooting
- I have read and followed the documentation AND the troubleshooting guide.
- I have searched other issues in this repository and mine is not recorded.
Source: kyverno/kyverno