Use of Password Hash With Insufficient Computational Effort Affecting jose package, versions >=1.10.0 <1.11.13


Severity

Recommended
0.0
high
0
10

CVSS assessment by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of Concept
EPSS
0.06% (1st percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications
  • Snyk IDSNYK-HEX-JOSE-21755409
  • published27 Oct 2026
  • disclosed26 Oct 2026
  • creditPeter Ullrich

Introduced: 26 Oct 2026

NewCVE-2026-65629  (opens in a new tab)
CWE-916  (opens in a new tab)

How to fix?

Upgrade jose to version 1.11.13 or higher.

Overview

Affected versions of this package are vulnerable to Use of Password Hash With Insufficient Computational Effort via the DER export path for password-encrypted private keys, which applies a PBKDF2 iteration count of only 2048 and an 8-byte (64-bit) salt when calling JOSE.JWK.to_der/2 with a secret password. An attacker who obtains the resulting EncryptedPrivateKeyInfo DER blob can recover the PBKDF2 parameters directly from the public structure of that blob, then mount an offline dictionary attack against the password using only the library's public decrypt path, recovering the private key at a work factor approximately 300 times below the OWASP-recommended 600,000 iterations with a 128-bit salt.

PoC

The attached script encodes an outside-attacker threat model in which the attacker holds nothing but the exported DER blob.

1. **Threat model.** A victim application calls the public entry point `JOSE.JWK.to_der(secret_password, jwk)` to export a password-encrypted RSA-2048 private key. The resulting `EncryptedPrivateKeyInfo` DER blob ends up somewhere readable — a backup, a config repository, object storage, or a log. The attacker obtains only that blob; they have no host access and make no internal function calls.

2. **Parameter recovery.** The script walks the DER structure by hand (a small tag/length/value parser) to pull the PBES2 → PBKDF2 parameters straight out of the public bytes, extracting the salt length and iteration count. It decodes them and prints, for example, an 8-byte (64-bit) salt and `iterationCount = 2048`, alongside the OWASP guidance of 600,000 iterations and ≥128-bit salt — demonstrating that the weak work factor is observable to anyone holding the blob.

3. **Offline crack.** The script then runs an offline dictionary attack using only the library's public decrypt path. Each candidate password is fed to `JOSE.JWK.from_der(candidate, der)`; a wrong password raises inside the cipher, and the correct one yields the private key. The real password is placed at the end of a 300-entry wordlist so the timing reflects many failed KDF evaluations — i.e. genuine cracking work. The crack is timed with `:timer.tc/1`, and the script reports elapsed time, cost per candidate, and the weakness factor (`600000 / iterations`, ≈300×).

4. **What proves the bug.** The script asserts `iterations < 600_000 and salt_bits < 128 and found == secret_password`. When all three hold it prints a `VERIFIED:` line stating the recovered parameters, the fact that the offline crack recovered the private key, and how far below the OWASP work factor the export sits. The full script is attached below under "Scripts and Logs" so the reader can run it themselves.

Note: The PoC section describes a script that demonstrates parameter recovery from a DER blob and an offline dictionary attack using the library's public decrypt path, but states no specific runtime, operating system, or non-default configuration.

CVSS Base Scores

version 4.0
version 3.1