Hi,
The following vulnerabilities were published for erlang-jose.
CVE-2026-65625[0]:
| The pure-Erlang AES-GCM fallback in jose_jwa_aes derives the number
| of verified authentication tag bits from the attacker-supplied tag
| itself. In the {aes_gcm, Bits} clause of block_decrypt/4, the
| incoming tag is guarded only by is_binary/1, with no check on its
| length. Verification in gcm_block_decrypt/6 then computes TBits =
| bit_size(T) and compares only those bits of the real 128-bit tag. An
| attacker who controls a JWE token can truncate the authentication
| tag to as little as 8 bits, so only 8 bits are ever checked. This
| reduces forgery resistance from 2^-128 to 2^-8, and a forged
| ciphertext is reliably accepted as authentic within 256 attempts
| without knowledge of the key (an authentication tag forgery and
| integrity bypass). Supplying a tag longer than 128 bits instead
| causes a badmatch that crashes the decrypting process. The fallback
| is reached through the public JWE decryption path whenever AES-GCM
| is not provided by a native crypto NIF, for example on FIPS or
| stripped or older OTP builds. This issue affects jose: from 1.2.0
| before 1.11.13.
CVE-2026-65626[1]:
| The pure-Erlang RSAES-PKCS1-v1_5 decryption in the jose_jwa_pkcs1
| module is a Bleichenbacher padding oracle. eme_pkcs1_decode/2
| returns the recovered message when a decrypted block has valid
| PKCS#1 v1.5 padding (a leading 0x00 0x02, a padding string of at
| least eight non-zero bytes, and a 0x00 separator) and returns a
| distinct error result otherwise, and rsaes_pkcs1_decrypt/2
| additionally returns {error, {badsize, _}} when the length check
| fails. The implementation applies no implicit-rejection
| countermeasure (RFC 8017 §7.2.2): it does not substitute a
| deterministic pseudo-random plaintext on a padding failure, so a
| one-bit padding-conformance signal leaks to the caller. Because the
| underlying modular exponentiation in dp/2 is a raw, non-blinded
| crypto:mod_pow/3, the padding check also stays distinguishable by
| timing even when an application normalizes every failure to a single
| error value. An unauthenticated attacker who knows only the public
| RSA key and can submit ciphertexts to a decryption endpoint that
| unwraps RSA1_5 JWE keys (or otherwise calls decrypt_private/3 with
| rsa_pkcs1_padding) can use this oracle to recover the plaintext of
| intercepted ciphertexts, such as content-encryption keys and thus
| the protected message, or to forge signatures, through roughly 10^4
| to 10^6 adaptive chosen-ciphertext queries. This issue affects
| jose: from 1.3.0 before 1.11.13.
CVE-2026-65627[2]:
| Improper Handling of Highly Compressed Data (Data Amplification)
| vulnerability in potatosalad jose (erlang-jose) allows a remote
| attacker to exhaust a node's memory with a small crafted JWE token.
| The jose_jwe_zip:uncompress/2 function in src/jwe/jose_jwe_zip.erl
| decompresses the DEFLATE-compressed plaintext of a JWE that carries
| the optional zip: DEF header by calling zlib:inflate/2 on the entire
| attacker-controlled stream, with no bound on the output size or the
| inflation ratio. Raw DEFLATE reaches ratios around 1000:1 on highly
| repetitive input, so a few-kilobyte token inflates to hundreds of
| megabytes or gigabytes in a single call. Decompression runs
| automatically during decryption through jose_jwe:block_decrypt/2
| (JOSE.JWE.block_decrypt/2 in Elixir), before the recipient can
| inspect or reject the payload. With the common asymmetric key-
| management algorithms (RSA-OAEP, ECDH-ES) an attacker needs only the
| recipient's public key to craft such a token, so no authentication
| or secret material is required. A single small token can exhaust the
| node's memory and crash the BEAM, denying service to all users.
| This issue affects jose: from 1.0.0 before 1.11.13.
CVE-2026-65628[3]:
| 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.
CVE-2026-65629[4]:
| Use of Password Hash With Insufficient Computational Effort in the
| jose library allows an attacker who obtains a password-encrypted
| private-key export to recover the private key through an offline
| password-cracking attack. When jose exports a password-encrypted
| private key with jose_jwk:to_der/2 (JOSE.JWK.to_der/2), the
| jose_jwk_der:to_binary/3 function in src/jwk/jose_jwk_der.erl
| serializes the key as a PKCS#8 EncryptedPrivateKeyInfo using the
| PBES2 scheme with hardcoded key-derivation parameters: PBKDF2-HMAC-
| SHA256 with an iteration count of 2048 and an 8-byte (64-bit) random
| salt. Neither value can be overridden by the caller. Both values
| are far below current guidance (OWASP recommends on the order of
| 600,000 iterations for PBKDF2-HMAC-SHA256, and NIST recommends salts
| of at least 128 bits), so the key-stretching work factor is roughly
| 300 times lower than intended and the short salt reduces the cost of
| precomputation across keys. The symmetric encryption (AES-256-CBC
| with a 16-byte random IV) is not affected; the weakness is entirely
| in the derivation strength. An attacker who obtains one of these
| exported blobs (for example from a backup, configuration repository,
| object storage, or logs) can mount a cheap offline dictionary or
| brute-force attack against the export password, and success yields
| the full private key. This issue affects jose: from 1.10.0 before
| 1.11.13.
CVE-2026-65630[5]:
| Observable Timing Discrepancy vulnerability in potatosalad jose
| allows recovery of a long-term X25519 private key through a timing
| side channel in the pure-Erlang Curve25519 fallback. The pure-
| Erlang X25519 implementation performs scalar multiplication over the
| secret private key using a recursive Montgomery ladder
| (jose_jwa_x25519:curve25519/2) whose clauses branch on individual
| bits of the clamped private scalar, and whose per-step operations
| (jose_jwa_x25519:montgomery_add/3 and
| jose_jwa_x25519:montgomery_double/1) and field inversion are built
| from value-dependent Erlang bignum arithmetic (multiplication,
| remainder, and modular exponentiation). Although the ladder is
| operation-count balanced and fixed at 254 steps, the concrete
| integer values processed at each step, and therefore the running
| time, depend on the secret scalar. The execution time of the public
| entry points jose_jwa_x25519:scalarmult/2, jose_jwa_x25519:x25519/2,
| jose_jwa_x25519:x25519_base/1, and jose_jwa_x25519:sk_to_pk/1 is
| thus a function of the private key. This path is reachable from the
| public API, most notably when a service decrypts attacker-supplied
| ECDH-ES (JWE) messages with a long-term X25519 key (for example
| through JOSE.JWK.box_decrypt_ecdh_es/2, which reaches
| jose_jwa_curve25519:x25519_shared_secret/2 and the ladder). An
| attacker who can submit ciphertexts and measure decryption timing
| can, in principle, recover the private key bit by bit, defeating the
| resistance X25519 was designed to provide. Recovery of the key
| compromises the confidentiality and authenticity of all data
| protected by it. This issue affects jose: from 1.10.0 before
| 1.11.13.
CVE-2026-65631[6]:
| Inefficient Algorithmic Complexity in erlang-jose allows an
| unauthenticated remote attacker to cause a CPU-exhaustion denial of
| service by submitting a crafted RSA JSON Web Key. When an
| application parses an untrusted JWK through the public
| jose_jwk:from_binary/1 or jose_jwk:from_map/1 API (or the Elixir
| wrappers JOSE.JWK.from_binary/1 and JOSE.JWK.from_map/1), an RSA
| private key that supplies d, e, and n but omits all Chinese
| Remainder Theorem parameters (p, q, dp, dq, qi) is routed into
| convert_sfm_to_crt/1, which tries to recover the missing primes by
| factoring the modulus. The three integers are read straight from the
| base64url input and are never validated as a real RSA key. When the
| modulus cannot be split into two factors (for example, when it is
| itself prime), the search loop convert_sfm_to_crt_find_p/6 performs
| a modular exponentiation over the attacker-sized modulus on every
| iteration and never succeeds. A single request of a few hundred
| bytes forces close to one CPU-second of work before an internal one-
| second watchdog kills the worker, and a larger modulus raises the
| cost further. By flooding such requests an attacker can saturate
| every scheduler and deny service, without credentials, a valid RSA
| key, or any special configuration. This issue affects jose: from
| 1.7.7 before 1.11.13.
CVE-2026-65632[7]:
| The jose library accepts ECDSA (ES256, ES256K, ES384, and ES512) JWS
| signatures of a non-canonical length. When verifying an ECDSA
| signature, jose_jwk_kty_ec:verify/4 in src/jwk/jose_jwk_kty_ec.erl
| splits the raw signature in half by its actual byte length
| (split_binary(Signature, byte_size(Signature) div 2)) instead of
| enforcing the fixed length required by RFC 7518 §3.4, and then
| decodes each half with crypto:bytes_to_integer/1, which ignores
| leading zero bytes. As a result, an attacker who holds one valid
| token can prepend leading zero bytes to each of the R and S halves
| to produce longer signatures that still split evenly and decode to
| the same (r, s) pair, so many distinct signature byte strings all
| verify against the same key (signature malleability). This does not
| allow forging new payloads or impersonating a signer, because the
| underlying (r, s) values are unchanged. It does defeat any security
| control that assumes a valid token or its signature is unique, such
| as token-revocation-by-hash, replay or idempotency caches, and
| deduplication logic. This issue affects jose: from 1.0.0 before
| 1.11.13.
If you fix the vulnerabilities please also make sure to include the
CVE (Common Vulnerabilities & Exposures) ids in your changelog entry.
For further information see:
[0] https://security-tracker.debian.org/tracker/CVE-2026-65625
https://www.cve.org/CVERecord?id=CVE-2026-65625
[1] https://security-tracker.debian.org/tracker/CVE-2026-65626
https://www.cve.org/CVERecord?id=CVE-2026-65626
[2] https://security-tracker.debian.org/tracker/CVE-2026-65627
https://www.cve.org/CVERecord?id=CVE-2026-65627
[3] https://security-tracker.debian.org/tracker/CVE-2026-65628
https://www.cve.org/CVERecord?id=CVE-2026-65628
[4] https://security-tracker.debian.org/tracker/CVE-2026-65629
https://www.cve.org/CVERecord?id=CVE-2026-65629
[5] https://security-tracker.debian.org/tracker/CVE-2026-65630
https://www.cve.org/CVERecord?id=CVE-2026-65630
[6] https://security-tracker.debian.org/tracker/CVE-2026-65631
https://www.cve.org/CVERecord?id=CVE-2026-65631
[7] https://security-tracker.debian.org/tracker/CVE-2026-65632
https://www.cve.org/CVERecord?id=CVE-2026-65632
Regards,
Salvatore