Skip to content

fast-jwt 6.2.4 treats raw public JWK JSON as an HMAC secret, enabling HS256 token forgery

High
SociableSteve published GHSA-g3jj-5cmm-3hxx Jul 28, 2026

Package

npm fast-jwt (npm)

Affected versions

= 6.2.4

Patched versions

6.3.0

Description

Summary

fast-jwt 6.2.4 silently classifies raw serialized public JWK JSON
as an HMAC secret.

If an application supplies public JWK JSON text as the verifier key and
HS256 is explicitly allowed or automatically inferred, an attacker who
knows the same public JSON text can use it as an HMAC key and create an
arbitrary HS256 token that fast-jwt accepts as valid.

This can result in authentication or authorization bypass through forged
JWT claims.

The PoC demonstrates the issue with a serialized RSA public JWK. The same
non-PEM classification also applies to raw JWKS JSON text, although the
attached standalone PoC focuses on the smallest JWK case.

Details

The verifier accepts a string or Buffer as key material. In
src/crypto.js, performDetectPublicKeyAlgorithms() attempts to infer
the permitted algorithm family from the supplied string.

Strings matching supported PEM public-key formats are classified as
asymmetric keys. Any other non-empty string is assumed to be an HMAC
secret:

function performDetectPublicKeyAlgorithms(key) {
  const trimmedKey = key.trim()
  const publicKeyPemMatch = trimmedKey.match(publicKeyPemMatcher)

  if (trimmedKey.match(privateKeyPemMatcher)) {
    throw new TokenError(
      TokenError.codes.invalidKey,
      'Private keys are not supported for verifying.'
    )
  } else if (
    publicKeyPemMatch &&
    publicKeyPemMatch[1] === 'RSA'
  ) {
    return rsaAlgorithms
  } else if (
    !publicKeyPemMatch &&
    !trimmedKey.includes(publicKeyX509CertMatcher)
  ) {
    // Not a PEM, assume a plain secret
    return hsAlgorithms
  }

  // ...
}

A serialized RSA, EC, or OKP public JWK is valid JSON, but it is not PEM
and does not contain a certificate header. It therefore reaches:

return hsAlgorithms

The HS256 verification path then uses the complete public JSON string as
the HMAC key.

Because JWK public-key material is public by design, an attacker can know
the verifier's cryptographic key material. When that public material is
reinterpreted as an HMAC secret, the attacker can calculate a valid
HS256 signature over arbitrary claims.

The vulnerable transition is:

Public asymmetric JWK JSON
        |
        v
Does not match PEM detection
        |
        v
Classified as a plain secret
        |
        v
HS256 permitted or inferred
        |
        v
Attacker signs using public JSON bytes
        |
        v
Forged token accepted

The attached PoC demonstrates both relevant configurations:

An explicit mixed-family allowlist:
createVerifier({
  key: rawJwk,
  algorithms: ['HS256', 'RS256']
})
No explicit algorithm allowlist:
createVerifier({
  key: rawJwk
})

In the second configuration, fast-jwt detects the raw non-PEM string as
symmetric key material and permits the HS algorithm family.

An RS256-only verifier rejects the same forged token, providing a
negative control:

createVerifier({
  key: rawJwk,
  algorithms: ['RS256']
})

The documentation describes asymmetric verifier keys as PEM-encoded
public keys. The security issue is not that the raw JWK is successfully
parsed as an asymmetric key. It is that ambiguous structured public-key
text is silently reclassified as a symmetric secret rather than being
rejected, and that this classification permits an attacker-controlled
HS256 token.

PoC

Requirements:

Node.js 20 or newer
npm
The attached submission ZIP

Extract the attachment and run:

cd poc
npm install
node poc.js

The PoC performs the following steps:

Generates a fresh RSA key pair locally.
Exports only the public key as a JWK.
Adds ordinary public JWK metadata such as kid, use, and alg.
Serializes the public JWK as JSON.
Uses the serialized public JWK text as an HS256 HMAC key.
Creates a token containing attacker-selected administrative claims.
Supplies the same raw public JSON string to the real
fast-jwt verifier.
Confirms acceptance with a mixed HS256/RS256 allowlist.
Confirms acceptance when algorithm detection is left enabled.
Confirms rejection with an RS256-only verifier.

Expected output:

mixed algorithms: forged token accepted
inferred algorithms: forged token accepted
RS256-only control: forged token rejected
VULNERABLE: fast-jwt@6.2.4 accepted attacker-signed HS256 claims

The accepted token contains:

{
  "sub": "attacker",
  "role": "admin",
  "admin": true
}

The PoC operates entirely locally using a newly generated key pair. It
does not contact any production service, identity provider, or
third-party application.

Impact

An affected application may accept attacker-generated JWT claims as
authentic.

Depending on how verified claims are used, an attacker could potentially
forge:

user or subject identifiers;
administrator roles;
authorization scopes;
permissions;
tenant or organization identifiers; and
application-specific authorization flags.

This may result in authentication bypass, horizontal privilege
escalation, vertical privilege escalation, or unauthorized access to
protected application data.

Exploitation requires all of the following:

The application passes raw serialized public JWK or JWKS JSON text as
the verifier key.
HS256 is explicitly permitted or is inferred from the non-PEM string.
The attacker knows the exact serialized bytes supplied to the
verifier.

Public JWK/JWKS material is normally available to relying parties and
often exposed through public discovery endpoints. However, property
ordering, whitespace, or other serialization differences may affect an
attacker's ability to reproduce the exact HMAC key bytes.

These integration and serialization requirements are represented by
High attack complexity.

Applications that supply a supported PEM public key and restrict
verification to the expected asymmetric algorithm family are not
affected by this PoC.

Earlier package versions were not assessed as part of this report.

Suggested remediation

Structured public-key representations should be detected before an
arbitrary non-PEM string is classified as symmetric key material.

At minimum, JSON strings containing asymmetric JWK or JWKS structures
should be rejected for HS* verification. Relevant asymmetric kty
values include:

RSA
EC
OKP

Potential approaches include:

Parse JSON-looking verifier strings before HMAC classification.
Reject asymmetric JWK/JWKS structures for HS256, HS384, and HS512.
Do not treat all non-PEM strings as symmetric secrets merely because
PEM detection failed.
Require explicit algorithm selection when the key format is
ambiguous.
Bind the permitted algorithm family to the semantic key type rather
than the success or failure of PEM detection.

Regression tests should cover:

compact serialized JWK JSON;
pretty-printed JWK JSON;
raw JWKS JSON;
RSA, EC, and OKP public keys;
mixed symmetric/asymmetric algorithm allowlists;
default algorithm detection;
asymmetric-only algorithm controls;
trailing whitespace and newline variants; and
property-order and serialization variants.
[fast-jwt-raw-jwk-hs256-submit.zip](https://github.com/user-attachments/files/30396435/fast-jwt-raw-jwk-hs256-submit.zip)

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
High
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

CVE ID

No known CVE

Weaknesses

Improper Verification of Cryptographic Signature

The product does not verify, or incorrectly verifies, the cryptographic signature for data. Learn more on MITRE.

Credits