Coordinated disclosureGHSA-g3jj-5cmm-3hxxfast-jwt · npm7.4 High

Proof/CVEs & advisories/GHSA-g3jj-5cmm-3hxx

GHSA.05 — Advisory credit

A public key became a shared secret.

An RSA public key is safe to publish because it verifies signatures without creating them. That model collapses the moment the same bytes are accepted as an HMAC secret — which is what fast-jwt 6.2.4 did with raw JWK JSON.

AdvisoryGHSA-g3jj-5cmm-3hxx
Packagefast-jwt
Ecosystemnpm · Node.js
Affected6.2.4
Fixed6.3.0
WeaknessCWE-347
Severity7.4 High
ReporterCharles Vosburgh
The selected JWT algorithm family must be cryptographically bound to the semantic key type. Asymmetric public material must never fall back to an HMAC byte string.
Weakness
CWE-347
Trigger
raw JWK JSON as key
Control
RS256-only rejects
Outcome
forged HS256 claims
What this is not.The attack does not recover or bypass the private RSA key. It succeeds because public asymmetric key material is reinterpreted as a shared symmetric secret. “RSA signatures can be forged” is the wrong summary; algorithm/key-type confusion is the right one.

JWT verification has two linked inputs: the token’s signature algorithm, and the semantic type of the verification key. Losing the second turns the first into an attacker’s choice.

The selected JWT algorithm family must be cryptographically bound to the semantic key type; asymmetric public material must never fall back to an HMAC byte string.

The vulnerable deployment prerequisites are specific:

  1. the application supplies raw serialized JWK/JWKS JSON as a string or buffer rather than converting it into a native asymmetric key object;
  2. the verifier accepts HS256 alongside an asymmetric family, or lets fast-jwt infer allowed algorithms; and
  3. the attacker knows the exact serialized public-key bytes used by the verifier, including property ordering and whitespace when a raw string is used.

An RS256-only verifier is not affected by the demonstrated HS256 forgery path.

In fast-jwt 6.2.4, algorithm detection distinguished recognizable PEM and certificate material from other strings. A non-empty string that was not recognized as PEM fell into the generic HMAC-secret branch:

Vulnerable classificationfast-jwt 6.2.4
} else if (!publicKeyPemMatch && !trimmedKey.includes(publicKeyX509CertMatcher)) {
  // Not a PEM, assume a plain secret
  return hsAlgorithms
}

Raw RSA, EC or OKP JWK JSON is not PEM and contains no X.509 header. The verifier therefore loses the semantic information that this string represents public asymmetric key material — even though the JSON’s own kty field says so explicitly.

Once the key is categorized as a secret, an HS256 token using the same serialized JSON bytes as its HMAC key is internally consistent from the verifier’s mistaken point of view.

1

Verifier is configured with raw public JWK JSON

A serialized string or buffer, not a native asymmetric key object.

2

An HS algorithm is allowed or inferred

Either a mixed-family allowlist, or algorithm inference.

3

fast-jwt classifies the JSON as an HMAC secret

The “not PEM” branch discards the asymmetric semantics.

4

The attacker obtains the same public bytes

They are public by design — that is the point of a public key.

5

Attacker-selected claims are signed with HS256

Using the serialized public JWK string as the HMAC key.

6

The vulnerable verifier accepts the forged token

No private key was ever needed.

Negative control

RS256-only verifier

Rejects the forged HS256 token — establishing that this is confusion, not signature forgery.

Vulnerable path

Mixed / inferred families

Exact 6.2.4 accepts the attacker-selected claims when HS256 is allowed or inferred alongside the asymmetric family.

Fixed control

6.3.0

Upstream regression tests executed locally and passed; asymmetric JSON structures are recognized before the secret fallback.

SETUP generate RSA pair, export PUBLIC jwk only FORGE HMAC-SHA-256 over attacker claims, key = serialized public JWK 6.2.4 mixed-family verifier: ACCEPTED 6.2.4 inference-enabled verifier: ACCEPTED CONTROL RS256-only verifier: REJECTED 6.3.0 upstream regression suite: PASS NO production JWT service, account, key or third-party endpoint used

The key parser used representation shape as a proxy for key semantics. “Not recognizable PEM” became “plain symmetric secret,” even when the string was structured JSON whose kty explicitly identified RSA, EC or OKP public-key material.

Cryptographic policy should fail closed when the key’s semantic type and the requested algorithm family disagree. Falling back from an unrecognized structured key to a generic secret converts intentionally public bytes into authentication material.
The SecHive research loop

Follow the key, not the file format.

Key-detection code is a natural place for security to leak, because it answers a parsing question and a policy question at the same time. The hypothesis was simple: find the branch that gives up on identifying a key and picks a default.

SK.01

Source mapping

Read the key-classification path and locate every fallback branch.

SK.02

Semantics hypothesis

Ask what happens when structured asymmetric material is unrecognized rather than malformed.

SK.03

Runtime construction

Forge HS256 claims using only the public JWK bytes; never touch the private key.

SK.04

Skeptic gate

Run the RS256-only control so the result reads as key-type confusion, not signature forgery.

HUMAN

Promotion and disclosure

Keep the published affected range as the publisher scoped it; test only owned keys.

The fixing commit is 10f9591349199ed2ab9fa1748ce92cdca697f6cf, released in fast-jwt 6.3.0. It recognizes JSON-looking key strings before the generic raw-secret fallback and rejects asymmetric structures being treated as symmetric key material. The guarded structures are:

  1. a top-level JWK with kty of RSA, EC or OKP;
  2. a JWKS containing asymmetric keys; and
  3. a bare array containing asymmetric JWK values.

Symmetric JWKs using kty: "oct" and ordinary opaque HMAC secrets remain valid. An explicitly all-HS caller is treated as an intentional assertion that the supplied material is meant to be symmetric; the fix targets the mixed-family and inferred cases where asymmetric semantics would otherwise be silently lost.

High
Published advisory severity
7.4
CVSS 3.1
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

Attack complexity is elevated because exploitation depends on a particular key representation and algorithm configuration, including knowledge of the exact serialized bytes used as the verifier key. Downstream effect depends on what the consuming application trusts from JWT claims — commonly impersonation, authorization bypass, or access granted by forged roles or identities.

ScopeValueBasis
Public affected version6.2.4advisory intentionally limits the range
Fixed6.3.0exact npm artifacts and matching tags inspected
Historical lineagee3ff09f07b55414e1fdaad2b8f225aa94832b45aolder refactor introducing the non-PEM-to-HMAC inference shape

That lineage does not expand the published affected range. Earlier releases were explicitly not assessed for the advisory and are not claimed affected here.

Upgrade to fast-jwt 6.3.0 or later. Applications should also make their intended cryptographic model explicit:

  1. convert JWK/JWKS data into native asymmetric key objects where appropriate;
  2. restrict verifiers to the expected algorithm family rather than mixed symmetric/asymmetric allowlists unless there is a compelling reason;
  3. reject keys whose semantic type conflicts with the selected JWT algorithm;
  4. avoid “unknown structured key ⇒ raw secret” fallback behaviour entirely.

Regression tests should cover RSA, EC, OKP and oct JWK values as top-level JWKs, JWKS documents, arrays, PEM strings and opaque secrets — across both inferred and explicit algorithm lists.

2026-07-28
GHSA-g3jj-5cmm-3hxx and the public PoC published.
2026
fast-jwt 6.3.0 published with the fix.
2026-08-26
Exact affected/fixed package artifacts and public regression tests reviewed.
  1. GHSA-g3jj-5cmm-3hxx — fast-jwt advisory and public PoC
  2. fast-jwt repository and release history
  3. fast-jwt release history

Credit: Discovered and reported by Charles Vosburgh. Research was AI-assisted through source mapping, hypothesis generation, release comparison and evidence organization; final validation, disclosure coordination, severity calibration and publication review remained human.