---
id: 2026-07-fast-jwt-rsa-hs256-algorithm-confusion-third-incomplete-fix-cve-batch
title: "fast-jwt (under @fastify/jwt, 1.3M weekly downloads): the second fix for RSA-to-HS256 algorithm confusion is bypassed again (CVE-2026-107722, 9.8, 6.2.0 to 6.2.4, fixed 6.3.0); raw JWK text treated as an HMAC secret, unsigned tokens accepted on an empty key, expired tokens served from cache; vendor July 28, CVEs 2026-10-08"
date_disclosed: 2026-07-28
last_updated: 2026-10-09
severity: critical
status: patched
ecosystems: [npm, nodejs, fastify, auth]
tools_affected: [fast-jwt, "@fastify/jwt", "Fastify and Node apps verifying RS256/ES256 tokens with fast-jwt and no asymmetric-only algorithms list"]
tags: [cve, jwt, algorithm-confusion, authentication-bypass, incomplete-fix, auth-primitive, backfill]
---

## TL;DR
**fast-jwt**, the JWT library that `@fastify/jwt` depends on (1,291,992 and 971,995 weekly npm downloads respectively, 2026-10-01 to 10-07), has now had the same RSA-to-HS256 algorithm-confusion bug fixed three times. **CVE-2023-48223** was the original. **CVE-2026-34950** (2026-04-02, 9.1) found that the fix's PEM-header check was anchored to the start of the string, so a leading space defeated it. **CVE-2026-107722** (vendor advisory 2026-07-28, CVE 2026-10-08, **CVSS 9.8**) finds that the second fix only trims whitespace, so any non-whitespace prefix, a comment, a control character, a zero-width character or wrapper text, still makes the library treat an RSA public key as an HMAC secret. An attacker who holds the public key signs HS256 tokens with it and the verifier accepts them. Affected **6.2.0 to 6.2.4**, fixed **6.3.0**. The same July batch adds raw JWK/JWKS text accepted as an HMAC secret (**CVE-2026-107724**, 7.4, 6.2.4 only), unsigned tokens accepted when the key is `''` or `null` and `algorithms` is set (**CVE-2026-107720**, 7.4, fixed 6.3.1), and a verifier cache that serves expired tokens for the cache TTL when `iat` is absent (**CVE-2026-107719**, 4.2, 2026-10-04, fixed 6.3.4). Upgrade to **6.3.4**, and set an asymmetric-only `algorithms` list, which the vendor says prevents the confusion attack regardless of version.

## What happened
The vendor published the July advisories on its own tab; GitHub assigned the CVEs on 2026-10-08, which is when the 9.8 reached the reviewed-critical npm listing. Dated by the vendor.

| Vendor date | Advisory | CVE | Score | Bug | Affected | Fixed |
|---|---|---|---|---|---|---|
| 2026-07-28 | GHSA-ww5h-9m49-7xx4 | CVE-2026-107722 | **9.8** | `performDetectPublicKeyAlgorithms` trims whitespace but `publicKeyPemMatcher` stays start-anchored, so a non-whitespace prefix skips PEM detection and the key falls through to the HMAC path | 6.2.0 to 6.2.4 | 6.3.0 (PR #632) |
| 2026-07-28 | GHSA-g3jj-5cmm-3hxx | CVE-2026-107724 | 7.4 | A serialised public JWK or JWKS passed as the verifier key is not recognised as asymmetric and is classified as a plain HMAC secret; an attacker who reproduces the exact string signs HS256 claims with it | 6.2.4 | 6.3.0 |
| 2026-07-30 | GHSA-8wpc-h4q6-8fxv | CVE-2026-107720 | 7.4 | `createVerifier` with `key: ''` or `null` and a non-empty `algorithms` list skips signature verification; an app whose secret comes from an unset environment variable accepts unsigned tokens | ≤ 6.3.0 | 6.3.1 |
| 2026-07-28 | GHSA-5hjw-83fp-phq9 | none seen | High | Silent claim-validator bypass when the JWT payload is a JSON array (title and severity from the tab; not opened) | | |
| 2026-07-28 | GHSA-687g-22h4-j4w4 | none seen | Moderate | `clockTolerance: Infinity` bypasses `exp` and `nbf` and persists in the verifier cache (title from the tab; not opened) | | |
| 2026-10-04 | GHSA-x937-hj6v-793p | CVE-2026-107719 | 4.2 | The cache deadline is taken from `exp` only when `iat` is present, so a token with `exp` and no `iat` stays valid in the cache for the default 10-minute TTL after it expired | ≤ 6.3.3 | 6.3.4 |

The preconditions matter for severity. The 9.8 needs a verifier that holds a public key and lets HS256 be inferred or allowed, which is the default shape when no `algorithms` option is set. An app that passes `algorithms: ['RS256']` is not exploitable on any version. The JWK variant needs raw JSON key text as the key. The empty-key variant needs a missing secret plus an explicit `algorithms` list, which is exactly what a misconfigured deployment looks like.

**Who consumes it.** `@fastify/jwt` 10.2.4 declares `fast-jwt: ^6.2.4`, so a fresh install today resolves to 6.3.4, but a lockfile that pinned 6.2.4 in July stays on the vulnerable version until it is regenerated. This is the JavaScript twin of the Python findings the corpus already carries: [PyJWT's PEM-detection bypass](2026-09-pyjwt-hmac-key-confusion-token-forgery-cve-batch.md) (CVE-2026-102268, 2026-09-29) and [python-jose's DER-key confusion](2026-09-python-jose-algorithm-confusion-unpatched-anyio-tls-idna-fastapi-stack-primitives.md) (CVE-2026-85394, unpatched). Every library that guesses the key type from its text has now been re-broken at least once in 2026.

**Credits.** dc-infosec and EchoSkorJjj (DC INFOSEC / n0l3x) for CVE-2026-107722; the-vibe-dev for CVE-2026-107724; Char0n1507 for CVE-2026-107720; SomnathDas, euriconicacio, BlueN0r and kagebunsher for CVE-2026-107719.

## Am I affected?
```bash
npm ls fast-jwt @fastify/jwt 2>/dev/null
grep -rn "createVerifier\|fastifyJwt\|@fastify/jwt" --include=*.js --include=*.ts . | grep -v node_modules | head
# vulnerable shape: a public key as `key` and no `algorithms` option, or `algorithms` set with an empty/unset key
```
Any resolved `fast-jwt` below 6.3.4 is missing at least one fix. The 9.8 applies to 6.2.0 through 6.2.4 when the verifier can infer HS256.

## If you are affected
1. Upgrade `fast-jwt` to **6.3.4 or later** and regenerate the lockfile so `@fastify/jwt`'s `^6.2.4` range actually resolves there.
2. Pass an explicit, asymmetric-only `algorithms` list to every verifier that uses a public key. The vendor states this prevents the attack on every version.
3. Make sure the signing secret or key cannot be empty: fail startup if the environment variable is unset.
4. If you cannot rule out forged tokens, rotate the signing key pair, which invalidates every token issued under it, and review authorisation logs for sessions that never went through login. See [if-your-webapp-was-compromised.md](../playbooks/if-your-webapp-was-compromised.md).

## Prevention
Never let the verifier infer the algorithm from the key material; the allowlist is the control ([credential-hygiene.md](../prevention/credential-hygiene.md)). Keep auth primitives on `latest` and run `npm audit` in CI, because these fixes shipped as patch releases with no changelog warning ([npm-hardening.md](../prevention/npm-hardening.md), [package-vetting-checklist.md](../prevention/package-vetting-checklist.md)).

## Sources
- [GitHub Advisory Database — GHSA-ww5h-9m49-7xx4: Incomplete patch of CVE-2026-34950: Non-whitespace key-prefix re-enables RSA→HS256 algorithm confusion](https://github.com/advisories/GHSA-ww5h-9m49-7xx4) (fetched 2026-10-09; CVE-2026-107722, 9.8 `AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H`, 6.2.0 to 6.2.4 → 6.3.0, repository advisory 2026-07-28, database 2026-10-08, PR #632, credits)
- [nearform/fast-jwt — Security Advisories](https://github.com/nearform/fast-jwt/security/advisories) (walked 2026-10-09; ten entries including the five of 2026-07-28/30 and the 2026-10-04 cache entry)
- [GHSA-g3jj-5cmm-3hxx — fast-jwt 6.2.4 treats raw public JWK JSON as an HMAC secret](https://github.com/nearform/fast-jwt/security/advisories/GHSA-g3jj-5cmm-3hxx) (CVE-2026-107724, 7.4, = 6.2.4 → 6.3.0), [GHSA-8wpc-h4q6-8fxv — createVerifier accepts unsigned JWTs when key is '' or null](https://github.com/nearform/fast-jwt/security/advisories/GHSA-8wpc-h4q6-8fxv) (CVE-2026-107720, 7.4, ≤ 6.3.0 → 6.3.1), [GHSA-x937-hj6v-793p — Verifier cache accepts expired JWTs without iat](https://github.com/nearform/fast-jwt/security/advisories/GHSA-x937-hj6v-793p) (CVE-2026-107719, 4.2, ≤ 6.3.3 → 6.3.4)
- [CVE Services — CVE-2026-107722](https://cveawg.mitre.org/api/cve/CVE-2026-107722), [CVE-2026-107724](https://cveawg.mitre.org/api/cve/CVE-2026-107724), [CVE-2026-107720](https://cveawg.mitre.org/api/cve/CVE-2026-107720), [CVE-2026-107719](https://cveawg.mitre.org/api/cve/CVE-2026-107719) (GitHub as CNA, all published 2026-10-08) and [CVE-2026-34950](https://cveawg.mitre.org/api/cve/CVE-2026-34950) (2026-04-06, 9.1, ≤ 6.1.0, the whitespace-prefix bypass of CVE-2023-48223)
- [GitHub Advisory Database — reviewed critical npm listing](https://github.com/advisories?query=type%3Areviewed+ecosystem%3Anpm+severity%3Acritical) (where the 2026-10-08 row surfaced); registry data via `npm view @fastify/jwt dependencies.fast-jwt` (`^6.2.4`), `npm view fast-jwt version` (6.3.4) and `api.npmjs.org` weekly download points, all 2026-10-09
