Infinite recursion (CPU denial-of-service) in JOSE.JWK.shared_secret/2 on mismatched key types
Impact
jose_jwk:shared_secret/2 (exposed in Elixir as JOSE.JWK.shared_secret/2) derives an ECDH shared secret from two JWKs. Its first function clause only matches when both JWKs carry the same key type (kty) module, and its fallback clause re-invokes itself as shared_secret(from(YourJWK), from(MyJWK)). Because from/1 returns an already-parsed jose_jwk record unchanged, passing two JWKs whose key types differ (for example an EC key and an RSA key) makes the fallback clause re-enter with identical arguments, producing an unbounded tail-recursive loop that never returns and never crashes.
Source excerpt · OSVWhat to do
Before calling JOSE.JWK.shared_secret/2, verify that the externally supplied peer key's type (kty) and curve match your own key, and reject any key whose type does not match before attempting derivation.
Affected packages
Start with the recorded fix for your release branch. Check your installed version and test compatibility before upgrading. Fixing this advisory does not rule out other vulnerabilities in the release.
| Affected range | Recorded fix |
|---|---|
| From 1.5.0 before 1.11.13Semantic versions | 1.11.13 |
Version evidence: OSV · EEF-CVE-2026-65628
View original version evidence (35 explicit versions)
Affected products
Vendor version evidence. Product records are separate from automatic dependency matching.
potatosalad · jose
Other versions: unaffected
| Version / range | Source status |
|---|---|
| 1.5.0 to before 1.11.13 | affected |
potatosalad · jose
Other versions: unaffected
| Version / range | Source status |
|---|---|
| 7b80b9f55b9898e1a6901ce136061b241b021d7c to before 26182a7de63b91550035d3f08741f7d17f1f675a | affected |
Original source description
Summary
jose_jwk:shared_secret/2 (exposed in Elixir as JOSE.JWK.shared_secret/2) derives an ECDH shared secret from two JWKs. Its first function clause only matches when both JWKs carry the same key type (kty) module, and its fallback clause re-invokes itself as shared_secret(from(YourJWK), from(MyJWK)). Because from/1 returns an already-parsed jose_jwk record unchanged, passing two JWKs whose key types differ (for example an EC key and an RSA key) makes the fallback clause re-enter with identical arguments, producing an unbounded tail-recursive loop that never returns and never crashes.
An application that derives a shared secret from an externally supplied peer public key without first checking that the peer key's type and curve match its own key can be driven into this loop by an attacker-controlled JWK, pinning an Erlang scheduler at 100% CPU. Repeated requests exhaust the available schedulers, resulting in a denial of service.
This issue affects jose: from 1.5.0 before 1.11.13.
Workarounds
Before calling JOSE.JWK.shared_secret/2, verify that the externally supplied peer key's type (kty) and curve match your own key, and reject any key whose type does not match before attempting derivation.
Source version evidence
This source records affected versions without identifying a package ecosystem and name. This evidence is not used for package matching.
References
- Security advisory github.com/potatosalad/erlang-jose/security/advisories/GHSA-fpj2-9h59-32pp
- Security advisory cna.erlef.org/cves/CVE-2026-65628.html
- Patch github.com/potatosalad/erlang-jose/commit/7b80b9f55b9898e1a6901ce136061b241b021d7c
- Patch github.com/potatosalad/erlang-jose/commit/26182a7de63b91550035d3f08741f7d17f1f675a
- Source reference hex.pm/packages/jose
- Security advisory osv.dev/vulnerability/EEF-CVE-2026-65628