We are happy to release KEDA 2.21.0 🎉
Important
KEDA 2.21.0 contains three breaking changes. If you are upgrading from KEDA 2.20, review Upgrading from KEDA 2.20 to 2.21 before upgrading.
Before upgrading from KEDA 2.20
Service account token audience enforcement (CVE-2026-77524)
KEDA 2.21 fixes the critical CVE-2026-77524 / GHSA-637c-6jxx-4rwm. You are affected if you use:
- Vault Kubernetes authentication, including configurations using the operator token, an existing projected token, or
credential.serviceAccountName. - Any
TriggerAuthenticationorClusterTriggerAuthenticationusingboundServiceAccountToken, including integrations with Metrics API, Prometheus, Loki, Datadog Cluster Agent, and other token-authenticated receivers.
You are not affected if you use ordinary Vault token authentication, API keys, OAuth credentials, or another authentication method that does not use a bound service account token. Before upgrading, review carefully the upgrade guide
Temporal Rules-Based Versioning settings
The Temporal scaler no longer accepts the deprecated buildId, selectAllActive, and selectUnversioned settings. Existing ScaledObjects and ScaledJobs containing them will fail scaler metadata parsing. Remove the settings for unversioned workers, or migrate versioned workers to workerDeploymentName and workerDeploymentBuildId. See Temporal Rules-Based Versioning settings.
Azure Pipelines in-flight jobs
KEDA 2.21 adds scaleOnInFlight, defaulting to true. Queue length now includes unfinished jobs already assigned to an agent. Set scaleOnInFlight: false to retain the unassigned-only behavior from KEDA 2.20; for ScaledJobs, combine this with the accurate scaling strategy. See Azure Pipelines in-flight jobs.
Highlights
- Reduce redundant scaler-backend requests when the HPA already owns the scaling decision (#7999, #8031).
- Add Azure Cosmos DB Change Feed, ClickHouse, and GCP Cloud Spanner scalers.
- Let external scalers update HPA targets dynamically through
StreamMetricSpec, and expose external-scaler gRPC client metrics. - Add Prometheus OAuth2 client-credentials authentication, Kafka Kerberos credential-cache support, and Azure Pipelines service-principal authentication.
- Improve scaler and authentication lifecycles with deterministic cancellation, refresh handling, Kubernetes API timeouts, and external-scaler connection cleanup.
Deprecation notice
The Liiklus scaler is deprecated because the upstream project is unmaintained. Its code is planned for removal in a later KEDA release. See #7929.
Learn how to deploy KEDA by reading our documentation.
🗓️ The next KEDA release is currently estimated for the 2nd week of January 2027. Learn more in our roadmap.
Breaking Changes
1e21cc7: Security: Enforce explicit service account token audiences to prevent TriggerAuthentication privilege escalation (CVE-2026-77524 / GHSA-637c-6jxx-4rwm; migration guide) (@wozniakjan)587d3cd: Azure Pipelines Scaler: Include assigned, unfinished jobs by default withscaleOnInFlight: true(#7905; migration guide) (@dttung2905)54a6651: Temporal Scaler: Remove deprecatedbuildId,selectAllActive, andselectUnversionedsettings (#7985; migration guide) (@omkar619-dev)
Deprecations
5744068: Liiklus Scaler: Deprecate the scaler because its upstream project is unmaintained; removal is planned for a later KEDA release (#7938, #7929) (@Copilot)
New
14c25e5: General: Accept pod-level cpu/memory requests in ScaledObject validation (#8119) (@ku524)7a4c241: General: controller sharding by label selectors (#7816) (@rossanorbr)28ab751: General: Add new GCP Cloud Spanner Scaler (#7844) (@n0rm4l-me)82ac584: General: Support StreamMetricSpec RPC in external scaler proto for dynamic HPA target updates (#7794) (@Fedosin)a84afd5: General: Add new Clickhouse Scaler (#7850) (@izaakschroeder)7775bbd: ActiveMQ Scaler: Allow managementEndpoint to be set via TriggerAuthentication (#8129) (@AymenSunstice)cbfc3f4: Azure Cosmos DB: Introduce new Azure Cosmos DB Change Feed Scaler (#7557) (@yash2710)2f37c71: Azure Monitor Scaler: Add optionalmetricIntervalmapping to the Azure Monitor interval parameter (#7526) (@nicknikolakakis)b505912: Kafka Scaler: support GSSAPI authentication with a Kerberos credential cache (#8069) (@Aytida-dev)f136606: Metrics: Add external scaler gRPC client metrics (#8199) (@aliaqel-stripe)c92573e: Prometheus Scaler: Add support for OAuth2 client credentials authentication (#8064) (@thde)51defd5: Selenium Grid Scaler: add includeOngoingSessions trigger param (#8107) (@VietND96)7548d04: Splunk Observability Scaler: Add sum, count, latest aggregators (#8098) (@js4683)c4511a2: Sumologic Scaler: add support ignoreNullValues (#8117) (@rickbrouwer)9a991fa: Temporal Scaler: add composite metric (backlog + running workflow count) (#7460) (@Sanil2108)8360d22: Temporal Scaler: add enableTLS parameter to control TLS with API key auth (#7854) (@LiorRabin)
Improvements
95701bd: General: Include release notes automatically replacing changelog.md (#7990) (@JorTurFer)eb9a985: General: Add flag to enable high-cardinality HTTP duration labels (#7751) (@aliaqel-stripe)e7a7d70: General: extract shared AuthMetadata struct for GCP scalers to eliminate duplicate credential fields (#8074) (@n0rm4l-me)7afd9a0: General: migrate datadog, graphite and github_runner, rabbitmq to authentication.Config (#7767) (@rickbrouwer)87d6244: General: stop polling triggers when pollingInterval is not relevant (#8031) (@rickbrouwer)8e9247d: General: use scorecard.dev API badge in README (#7913) (@rickbrouwer)4bd9fe1: General: Share HTTP Transport across HTTP clients to avoid leaking connections (#7941) (@aliaqel-stripe)88b0844: General: Aggregate KEDA CRD permissions into default roles (#7872) (@amarkdotdev)b1e8ee5: General: move HPA health signal off Ready into a dedicated HPAActive condition (#7928) (@vishnu97770)a673796: Azure Pipelines Scaler: add service principal authentication via reusable Azure provider (#7931) (@m-amaresh)617d0a3: MSSQL Scaler: Add driverName to select the azuresql driver (#8120) (@DinethShakya23)fac27c5: Azure Scalers: add unit tests for Azure cloud environment resolution (#7859) (@Goutham-Annem)82aede7: AWS Scalers: Add unit tests for GetAwsAuthorization (#7836) (@archy-rock3t-cloud)a45f085: GCP Scalers: Add unit tests for GetGCPAuthorization (#7837) (@archy-rock3t-cloud)
Fixes
5b34e20: General: Fix concurrent map iteration and map write in pkg/fallback (#7843) (@jiyuchen-stripe)f193c7f: General: Fix nil pointer dereference in customScalingStrategy when customScalingQueueLengthDeduction is omitted (#7871) (@itxaiohanglover)01cee0f: General: Guard against negative metric returned in scaler.go (#7889) (@dttung2905)a9c246e: General: Fix panic in the HashiCorp Vault token renewal (#7940) (@archy-rock3t-cloud)e794e30: General: Ignore StreamMetricSpec updates that carry no metric specs (#8116) (@Fedosin)8b4f083: General: Keep cached metric records of healthy triggers on scaler errors (#8073) (@rickbrouwer)41272b2: General: Make cache deletion synchronous to fix concurrency bug in CachedMetrics (#8067) (@KengoA)1e3954f: General: Timeout for Kubernetes API operations in scaling loops (#8174) (@josefkarasek)db72b7c: General: fix context handling for scalers and auth refreshes (#8195) (@wozniakjan)ee8a4dd: General: Restore gRPC reconnect backoff (#7857) (@simplyaduck)c5b577c: General: Guard GetCurrentReplicas against nil ScaleTargetGVKR (#7661) (@ggarb)97e1bd3: General: use field indexes in verifyScaledObjects to avoid O(N) admission cost (#7681) (@ggarb)ed8f3db: General: Fix concurrent map writes panic in the shared root CACertPool(#7911) (@BojanZelic)b4fc3fb: General: add "default" to ScaledJob scalingStrategy.strategy CRD enum (#7858) (@Goutham-Annem)637c98e: General: correct pollingInterval and cooldownPeriod relevance check for idleReplicaCount (#7984) (@rickbrouwer)dad6e70: General: Emit ScaledJob removal event with the ScaledJob's namespace (#7968) (@tczhao)5b81441: General: Grant events permission on both core and events.k8s.io groups (#7923) (@linkvt)ed5758d: General: Fix nil ptr dereference on uninitialized Deployment spec replicas (#7925) (@wozniakjan)68d8aaa: General: scaler scheme: recurse on nested pointers and propagate 'optional' (#8128) (@wozniakjan)f2f5cf0: General: Fix stale scalercache (#8125) (@GnatorX)8141d2e: CouchDB Scaler: Close the query result iterator instead of leaking the response body (#7907) (@vidigoat)86a4ebf: Dynatrace Scaler: Handle all documented DQL query states in execute and poll paths (#7986) (@jcrosel)035585f: External Scaler: release pooled gRPC connections when the last scaler closes (#8193) (@harshrajdebug)8d426ed: External Push Scaler: Activation send blocking on stream cancellation (#8170) (@shashankvarma499)4fb4084: Github Scaler: key per-run job cache by (repo, runID) (#7952) (@hontarenko)2f4ebfd: Kafka Scaler: Exclude retention-deleted messages from lag for uncommitted offsets (#7937) (@Nikko-Foti)778907e: Metrics API Scaler: reject auth modes the scaler does not implement (#8178) (@rickbrouwer)2963aa3: Metrics Service: Rebuild CA cert pool on rotation to prevent data race and monotonic growth (#8126) (@zanarellidev)d010627: RabbitMQ scaler: fix empty queue handling during fast drain (#8033) (@wozniakjan)4b7a369: Solr Scaler: fail on non-200 instead of reporting an empty queue (#8037) (@PrazwalR)0a7815a: Splunk Observability Scaler: Close SignalFlow client on teardown (#8134) (@js4683)3a4a73e: Azure Blob Scaler: strip leading slash from globPattern before matching (#7876) (@Goutham-Annem)0419a25: CI: replace status check functions in with: expressions (#7970) (@rickbrouwer)6f589e7: Mongo Scaler: Disconnect client when initial Ping fails to avoid leaking connections (#7904) (@orfeldman-evolinq)6375f8b: Kafka Scaler: Metadata scoping (#7886) (@Heniland)9d0ec6f: Azure EventHub Scaler: Avoid passing EventHubName when connection string contains EntityPath (#7926) (@njuCZ)503abe3: AWS Secret Manager: Guard nil credentials in handler (#7932) (@sobol-sudo)
Other
145db7f: General: Automate cherry-pick backports via labels (#7987) (@JorTurFer)0a86363: General: Improve e2e comments check to reduce agent usage (#7988) (@JorTurFer)72a80b7: General: Improve release notes sorting the entries (#8041) (@JorTurFer)5fc9e32: General: Some improvements related with release notes generation (#8010) (@JorTurFer)cd4bffc: CI: pin Argo Rollouts e2e dependency (#8095) (@linkvt)a608b83: CI: use server-side apply for Argo Rollouts (#8094) (@linkvt)0992d51: CI: fix broken helper.go links in tests README (#7867) (@s3onghyun)
CI
Show
25e37bd: CI: Add e2e coverage for paused annotation precedence (#7849) (@aliaqel-stripe)97d2d26: CI: Force KEDA resources deletion after e2e tests (#8042) (@JorTurFer)bf1ea1d: CI: assert what the nil identity id tests claim to check (#8024) (@Fedosin)d14108c: CI: defer cleanup in file_based_auth so the ClusterTriggerAuthentication cannot leak (#8027) (@Fedosin)d4f6918: CI: install optional e2e components based on per-test dependency markers (#8038) (@rickbrouwer)3146a35: CI: keep waiting when a KedaEventually condition cannot be observed (#8025) (@Fedosin)39396ed: CI: make the mysql readiness probe mean mysql is reachable (#8029) (@Fedosin)258b628: CI: mongodb and selenium activation tests watch a window instead of sleeping through it (#8154) (@Fedosin)e6ad4ed: CI: re-enable splunk o11y e2e tests (#8012) (@circa10a)aeb7920: CI: replica-ready waits must observe the rollout, not just the count (#8035) (@Fedosin)e48976d: CI: wait for pods to be ready, not merely running (#8026) (@Fedosin)bb4ad4a: CI: wait for the first job instead of sleeping one polling interval (#8028) (@Fedosin)87df4de: RabbitMQ scaler: close test HTTP servers (#8076) (@Karthik-Chowdary)58229df: CI: surface setup/teardown failures in the /run-e2e PR comment (#7809) (@wozniakjan)0882549: CI: e2e azure_pipelines scope build cleanup to own definition (#7982) (@wozniakjan)6038302: CI: e2e eventemitter/azureeventgridtopic drain foreign events from subscription (#7980) (@wozniakjan)38428b1: CI: e2e forgejo bump scale-in timeout 1min -> 3min (#7934) (@wozniakjan)0f2c27e: CI: e2e rabbitmq eqct purge queue before scale-in assertion (#7981) (@wozniakjan)8ac846f: CI: e2e selenium pre-pull browser node images before scaling assertions (#7979) (@wozniakjan)586aca8: CI: e2e vault wait for vault pod ready (#7978) (@wozniakjan)2f91d45: CI: enhance forgejo scale-in diagnostics (#7921) (@wozniakjan)8d1a3c8: CI: ensure e2e check runs are always finalized instead of left hanging (#7965) (@rickbrouwer)ee6a361: CI: SJ started scalers event + flaky e2e fixes (#7820) (@wozniakjan)02cd4dd: CI: address github_runner e2e test flakiness (#7842) (@wozniakjan)f126bef: CI: don't let a failed API read satisfy an e2e wait (#7996) (@Fedosin)23c3fd8: CI: wait for metrics instead of sleeping in opentelemetry_metrics (#7974) (@Fedosin)bf09609: CI: wait for the pause to take effect in pause_scaledobject_explicitly (#7975) (@Fedosin)e4b2d9b: CI: wait for the status CheckKubectlGetResult reads (#8023) (@Fedosin)7e62f2d: CI: wait for what the assertions read in prometheus_metrics (#7992) (@Fedosin)
Dependencies
Show
a46a435: General: Bump dependencies (#8092) (@JorTurFer)47c5e05: General: Include missing package in k8s group (#8146) (@JorTurFer)d581d84: Dependencies: Bump Go dependencies and migrate major versions (#8133) (@JorTurFer)ccde973: Dependencies: Pin dependencies (#8043) (@renovate[bot])fce92ac: Dependencies: Update AWS SDK (#8013) (@renovate[bot])d2634e6: Dependencies: Update AWS SDK (#8044) (@renovate[bot])4921f23: Dependencies: Update AWS SDK (#8078) (@renovate[bot])e9b43ec: Dependencies: Update AWS SDK (#8131) (@renovate[bot])25646fc: Dependencies: Update AWS SDK (#8205) (@renovate[bot])7b02c74: Dependencies: Update Azure SDK (#8014) (@renovate[bot])8d8a9d8: Dependencies: Update DevContainer (#8015) (@renovate[bot])34fd67b: Dependencies: Update GitHub Actions (non-major) (#8016) (@renovate[bot])b8d971a: Dependencies: Update GitHub Actions (non-major) (#8045) (@renovate[bot])e39dad2: Dependencies: Update GitHub Actions (non-major) (#8081) (@renovate[bot])c33e3dd: Dependencies: Update GitHub Actions (non-major) (#8102) (@renovate[bot])e0fe146: Dependencies: Update GitHub Actions (non-major) (#8139) (@renovate[bot])2836084: Dependencies: Update GitHub Actions (non-major) (#8149) (@renovate[bot])b4e70ae: Dependencies: Update GitHub Actions (non-major) (#8181) (@renovate[bot])5a7df86: Dependencies: Update GitHub Actions (non-major) (#8208) (@renovate[bot])87e669d: Dependencies: Update Go Dependencies (non-major) (#8017) (@renovate[bot])7d9d46f: Dependencies: Update Go Dependencies (non-major) (#8048) (@renovate[bot])69dfda9: Dependencies: Update Go Dependencies (non-major) (#8082) (@renovate[bot])f18f341: Dependencies: Update Go Dependencies (non-major) (#8180) (@renovate[bot])31d3335: Dependencies: Update Go Dependencies (non-major) (#8206) (@renovate[bot])2caeb4e: Dependencies: Update Google Cloud SDK (#8018) (@renovate[bot])a55aba1: Dependencies: Update Google Cloud SDK (#8132) (@renovate[bot])a38cbef: Dependencies: Update Kubernetes Dependencies to v0.35.7 (#8019) (@renovate[bot])b35d0da: Dependencies: Update Prometheus Dependencies (#8050) (@renovate[bot])8aefeff: Dependencies: Update Test Infrastructure (misc) (#8143) (@renovate[bot])8031a88: Dependencies: Update actions/github-script action to v9 (#8022) (@renovate[bot])2bbe2d3: Dependencies: Update dependency golangci/golangci-lint to v2.13.2 (#8080) (@renovate[bot])e377401: Dependencies: Update dependency protocolbuffers/protobuf to v35 (#8051) (@renovate[bot])26fa426: Dependencies: Update dependency protocolbuffers/protobuf to v36 (#8144) (@renovate[bot])7dae9ee: Dependencies: Update dependency protocolbuffers/protobuf to v36.2 (#8207) (@renovate[bot])7bd8b36: Dependencies: Update dependency strimzi/strimzi-kafka-operator to v1 (#8150) (@renovate[bot])e68aea9: Dependencies: Update gcr.io/distroless/static:nonroot Docker digest to 1c2c046 (#8077) (@renovate[bot])c045e79: Dependencies: Update gcr.io/distroless/static:nonroot Docker digest to e2e927e (#8179) (@renovate[bot])3b30c36: Dependencies: Update ghcr.io/kedacore/keda-tools Docker tag to v1.26.6 (#8101) (@renovate[bot])aa77c63: Dependencies: Update ghcr.io/kedacore/keda-tools Docker tag to v1.26.8 (#8148) (@renovate[bot])1bff632: Dependencies: Update golang Docker tag to v1.26.6 (#8046) (@renovate[bot])bf289bf: Dependencies: Update golang Docker tag to v1.27.1 (#8083) (@renovate[bot])9a56f69: Dependencies: Update kind Test Infrastructure (#8164) (@renovate[bot])372ab72: Dependencies: Update module cloud.google.com/go/storage to v1.65.0 (#8084) (@renovate[bot])7dff6d4: Dependencies: Update module github.com/Azure/azure-sdk-for-go/sdk/azcore to v1.23.0 (#8020) (@renovate[bot])f2179a0: Dependencies: Update module github.com/google/cel-go to v0.29.0 [SECURITY] (#8001) (@renovate[bot])f97d419: Dependencies: Update module github.com/google/cel-go to v0.30.0 [SECURITY] (#8071) (@renovate[bot])4f72bad: Dependencies: Update module github.com/google/go-github/v91 to v92 (#8209) (@renovate[bot])615d215: Dependencies: Update module github.com/klauspost/compress to v1.18.7 [SECURITY] (#8000) (@renovate[bot])4ee3f7e: Dependencies: Update module github.com/prometheus/prometheus to v0.311.3 [SECURITY] (#8004) (@renovate[bot])3860231: Dependencies: Update module github.com/valyala/fasthttp to v1.70.0 [SECURITY] (#8072) (@renovate[bot])79a0956: Dependencies: Update module golang.org/x/crypto to v0.56.0 [SECURITY] (#8118) (@renovate[bot])942a2b7: Dependencies: Update module golang.org/x/mod to v0.40.0 [SECURITY] (#8032) (@renovate[bot])abbd6ef: Dependencies: Update module golang.org/x/net to v0.56.0 [SECURITY] (#8002) (@renovate[bot])0931e90: Dependencies: Update module google.golang.org/grpc to v1.82.1 [SECURITY] (#8005) (@renovate[bot])56b8f23: Dependencies: Update pre-commit hook pre-commit/pre-commit-hooks to v6 (#8147) (@renovate[bot])93dfbbd: Dependencies: Update pre-commit hook thlorenz/doctoc to v2.5.0 (#8021) (@renovate[bot])c66db1b: Dependencies: Update s390x Test Infrastructure (major) (#8145) (@renovate[bot])dad9ffb: bump go to 1.26.5 (#7971) (@philipyzhang)89ac006: bump golangci lint (#7814) (@zroubalik)3f63bf5: chore(deps): bump github.com/microsoft/go-mssqldb from 1.9.6 to 1.10.0 (#7825) (@dependabot[bot])eafb8aa: chore(deps): bump the github-actions group across 1 directory with 12 updates (#7884) (@dependabot[bot])3f11d7e: chore(deps): bump the github-actions group across 1 directory with 13 updates (#7963) (@dependabot[bot])0dd3792: chore(deps): update github actions (#7873) (@renovate[bot])2f4cb43: chore(deps): update github actions (#7909) (@renovate[bot])06fb945: chore(deps): update github actions (major) (#7869) (@renovate[bot])5d3fe4b: chore(deps): update github actions to v6.0.3 (#7834) (@renovate[bot])5191d83: chore: fix duplicate (patch) suffix in Renovate k8s group name (#8007) (@linkvt)a3698f1: chore: improve Renovate dependency grouping (#8006) (@linkvt)64d8361: Dependencies: Remove optional replace directives from go.mod (#7821) (@linkvt)b618310: chore: remove vendored dependencies (#7839) (@linkvt)b5a6095: chore: replace Dependabot with Renovate (#7841) (@linkvt)74b33b1: chore: use Dependencies: prefix for Renovate PR titles (#8008) (@linkvt)c28ee2c: fix(deps) Bump prometheus to v0.312.0 to fix CVEs (#7882) (@rlanhellas)
New Contributors
- @jiyuchen-stripe made their first contribution in #7843
- @izaakschroeder made their first contribution in #7850
- @Goutham-Annem made their first contribution in #7858
- @s3onghyun made their first contribution in #7867
- @simplyaduck made their first contribution in #7857
- @itxaiohanglover made their first contribution in #7871
- @Heniland made their first contribution in #7886
- @amarkdotdev made their first contribution in #7872
- @orfeldman-evolinq made their first contribution in #7904
- @Sanil2108 made their first contribution in #7460
- @LiorRabin made their first contribution in #7854
- @vishnu97770 made their first contribution in #7928
- @sobol-sudo made their first contribution in #7932
- @n0rm4l-me made their first contribution in #7844
- @tczhao made their first contribution in #7968
- @njuCZ made their first contribution in #7926
- @philipyzhang made their first contribution in #7971
- @hontarenko made their first contribution in #7952
- @rossanorbr made their first contribution in #7816
- @jcrosel made their first contribution in #7986
- @PrazwalR made their first contribution in #8037
- @KengoA made their first contribution in #8067
- @Karthik-Chowdary made their first contribution in #8076
- @ku524 made their first contribution in #8119
- @omkar619-dev made their first contribution in #7985
- @DinethShakya23 made their first contribution in #8120
- @m-amaresh made their first contribution in #7931
- @GnatorX made their first contribution in #8125
- @AymenSunstice made their first contribution in #8129
- @shashankvarma499 made their first contribution in #8170
- @js4683 made their first contribution in #8098
- @vidigoat made their first contribution in #7907
- @nicknikolakakis made their first contribution in #7526
- @yash2710 made their first contribution in #7557
- @Aytida-dev made their first contribution in #8069
- @thde made their first contribution in #8064
- @Nikko-Foti made their first contribution in #7937
- @harshrajdebug made their first contribution in #8193
- @zanarellidev made their first contribution in #8126
Full Changelog: v2.20.0...v2.21.0