Skip to content

Fix CVE-2026-45363: upgrade jwt gem to 3.2.0#1693

Merged
zanejohnson-azure merged 1 commit into
ci_prodfrom
zanejohnson-azure/fix-jwt-cve-2026-45363
May 19, 2026
Merged

Fix CVE-2026-45363: upgrade jwt gem to 3.2.0#1693
zanejohnson-azure merged 1 commit into
ci_prodfrom
zanejohnson-azure/fix-jwt-cve-2026-45363

Conversation

@zanejohnson-azure
Copy link
Copy Markdown
Contributor

@zanejohnson-azure zanejohnson-azure commented May 18, 2026

Summary

Bumps the jwt gem from 2.7.1 to 3.2.0 to fix CVE-2026-45363 (HIGH) - Empty-key HMAC bypass.

Before After
jwt 2.7.1 3.2.0

Why a major version bump is safe for ama-logs

jwt is a third-party gem (not a default gem shipped with Ruby), and ama-logs uses an extremely small slice of its API. The only consumer is source/plugins/ruby/KubernetesApiClient.rb:

require "jwt"
...
@@TokenStr = File.read(@@TokenFileName).strip
begin
  token_info = JWT.decode(@@TokenStr, nil, false)   # unverified decode
  @@TokenExpiry = token_info[0]["exp"]
rescue JWT::DecodeError => e
  @Log.warn("The token is not a JWT.")
  ...
end

This is used purely to read the exp claim out of the in-pod service account token to know when to refresh it. No signing, no signature verification, no JWKs, no JWT::EncodedToken, no claim-verification helpers.

jwt 3.x breaking changes vs. this usage

Checked against the v3.0 upgrade guide:

Breaking change Affects us?
JWT::EncodedToken#payload raises before verification No - we use the legacy JWT.decode(token, key, verify) API
Stricter RFC 4648 base64 (no whitespace) No - we already .strip the token before decoding
Drop HS512256 algorithm No - no signing
Remove rbnacl dependency No - no EdDSA
RSA keys must be >= 2048 bits No - no signing
Custom algorithms must include JWT::JWA::SigningAlgorithm No - no custom algorithms
Removed deprecated claim verification methods No - we read payload["exp"] directly
Base64-encode k for HMAC JWKs No - no JWKs

JWT.decode(jwt, key=nil, verify=true, options={}, &keyfinder) has an identical signature in v3.2.0/lib/jwt.rb, and when verify=false the internal Decode#decode_segments returns [unverified_payload, header] - exactly as in 2.7.1. JWT::DecodeError is also unchanged.

Files changed

  • kubernetes/linux/setup.sh - gem_install_with_retry jwt -v "3.2.0"
  • kubernetes/windows/Dockerfile - gem install jwt -v 3.2.0

Testing

CI build + trivy scan on the resulting image confirms the CVE is gone. Functional path (token refresh in KubernetesApiClient.getTokenStr) exercises only the unchanged surface of the gem.

References


Validation: backdoor deployment on AKS test cluster

Deployed prod baseline (ciprod:3.3.0) and the test image with this change (cidev:3.3.0-26-gf10e2b232-20260519175254, jwt 3.2.0) to zane-ama-logs-helm-test3 and compared a 5-minute steady-state window (deploy+5 to deploy+10) for both.

Pods (test): 2 DS + 1 RS, all Running 3/3 (DS) / 2/2 (RS), 0 restarts.

LAW data volume per minute

Table Baseline Test Result
ContainerInventory 89,89,89,89,89 89,89,89,90,91 PASS (+1/+2 = new stale-pod-cleanup container)
KubeNodeInventory 2,2,2,2,2 2,2,2,2,2 PASS (exact match)
KubePodInventory 89,89,89,89,89 89,89,89,90,90 PASS (+1 = stale-pod-cleanup pod)
InsightsMetrics 89,89,89,89 (steady) 89,89,89,89 (steady) PASS
Perf 664,664,664,664,664 664,664,664,668,668 PASS (+4 = stale-pod-cleanup counters)
ContainerLogV2 ~599/min (log-gen) ~599/min (log-gen) PASS (overall drop = auoms-container stopped in cluster between windows; log-gen exact match)

jwt-specific signal

KubeMonAgentEvents in test window: 0 events, 0 jwt/token errors. Token-refresh path (KubernetesApiClient.getTokenStr -> JWT.decode(token, nil, false)) runs continuously and produced no JWT::DecodeError warnings.

Resource consumption (peak per minute, 5-min window)

Pod type Baseline memory Test memory Baseline CPU Test CPU
DS (agentpool) 233-244 MB 261-271 MB <0.013 cores <0.010 cores
DS (userpool) 234-243 MB 242-249 MB <0.013 cores <0.010 cores
RS 180-186 MB 175-182 MB <0.006 cores <0.006 cores

Memory variance (~5-25 MB on DS, RS lower) is within normal per-node workload variance. CPU is equal or lower in test. No regression.

Verdict: PASS - no data-ingestion regression, no jwt errors, no resource regression.

Bumps ruby-jwt from 2.7.1 to 3.2.0 to address CVE-2026-45363 (HIGH):
empty-key HMAC bypass.

Compatibility verified:
- Only usage in repo is source/plugins/ruby/KubernetesApiClient.rb,
  which calls JWT.decode(token, nil, false) (unverified decode) and
  rescues JWT::DecodeError. Both the JWT.decode signature and the
  JWT::DecodeError class are unchanged in jwt 3.x.
- Token is already .strip'd before decode, satisfying the stricter
  RFC 4648 base64 requirement introduced in jwt 3.0.
- No HMAC/RSA/ECDSA signing, JWT::EncodedToken, or claim-verification
  APIs are used, so none of the other jwt 3.0 breaking changes apply.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@zanejohnson-azure zanejohnson-azure requested a review from a team as a code owner May 18, 2026 22:58
@zanejohnson-azure zanejohnson-azure merged commit 29facc7 into ci_prod May 19, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants