HonoJS JWT/JWKS Algorithm Confusion

Table of Contents
Intro Lore
After spending some time looking for security issues in JS/TS frameworks, I moved on to Hono - fast, clean, and popular enough that small auth footguns can become "big internet problems".

This post is about two issues I found in Hono's JWT/JWKS verification path:
- a default algorithm footgun in the JWT middleware that can lead to forged tokens if an app is misconfigured
- a JWK/JWKS algorithm selection bug where verification could fall back to an untrusted
header.algvalue
Both were fixed in hono 4.11.4, and GitHub Security Advisories were published on January 13, 2026.


JWT / JWK / JWKS Primer
If you already have experience with JWT stuff, you can skip this:
- JWT is
base64(header).base64(payload).base64(signature). The header includesalg(the signing algorithm). - JWK is a JSON representation of a key (e.g. an RSA public key).
- JWKS is a set of JWKs, usually hosted at something like
/.well-known/jwks.json.
The key point here is that, algorithm choice must not be attacker-controlled.
Vulnerabilities
JWT middleware "unsafe default" (HS256)
Hono's JWT helper documents that alg is optional - and defaults to HS256.
That sounds harmless until you combine it with a very common real-world setup:
- The app expects RS256 (asymmetric)
- The developer passes an RSA public key string
- But they don't explicitly set
alg
In that case, the verification path defaults to HS256, treating that public key string as an HMAC secret, and that becomes forgeable because public keys are, well… public.
Why this becomes an auth bypass
If an attacker can generate a token that passes verification, they can mint whatever claims the application trusts (sub, role, isAdmin, etc.) and walk straight into protected routes.
This is the "algorithm confusion" class of bugs, where you think you're doing asymmetric verification, but you're actually doing symmetric verification with a key the attacker knows.
Who is affected?
This is configuration-dependent. The dangerous case is:
- you use the JWT middleware with an asymmetric public key and
- you don't pin
alg
The core issue is, Hono defaults to 'HS256', so a public key string can accidentally be used as an HMAC secret, allowing forged tokens and auth bypass.
Advisory / severity
Advisory: GHSA-f67f-6cw9-8mq4
This was classified as High (CVSS 8.2) and maps it to CWE-347 (Improper Verification of Cryptographic Signature).
Affected versions: < 4.11.4
Patched version: 4.11.4
JWK/JWKS middleware header.alg fallback
In the JWK/JWKS verification middleware, Hono could pick the verification algorithm like this:
- Use
jwk.algif present - Otherwise, fall back to
header.algfrom the JWT (unverified input)
GitHub's advisory spells it out, when the selected JWK doesn't explicitly define an algorithm, the middleware falls back to using the alg from the unverified JWT header - and since alg in JWK is optional and commonly omitted, this becomes a real-world issue.
If the matching JWKS key lacks alg, verifyWithJwks falls back to token-controlled header.alg, enabling algorithm confusion / downgrade attacks.
Why it matters
"Trusting header.alg" is basically letting the attacker influence how you verify the signature. Depending on surrounding constraints (allowed algorithms, how keys are selected, and how the app uses claims), this can lead to forged tokens being accepted and authz/authn bypass.
Advisory / severity
Advisory: GHSA-3vhc-576x-3qv4
This was classified as High (CVSS 8.2), also CWE-347, with affected versions < 4.11.4 and patched in 4.11.4.
The Fix
Both advisories took the same philosophical stance i.e. Make alg explicit. Don't infer it from attacker-controlled input.

Fix for #1 (JWT middleware)
The JWT middleware now requires an explicit alg option — a breaking change that forces callers to pin the algorithm instead of relying on defaults.
Before (vulnerable):
import { jwt } from 'hono/jwt'
app.use('/auth/*', jwt({
secret: '...',
// alg was optional
}))
After (patched):
import { jwt } from 'hono/jwt'
app.use('/auth/*', jwt({
secret: '...',
alg: 'HS256', // required
}))
(Example configuration shown in the advisory.)
Fix for #2 (JWK/JWKS middleware)
The JWK/JWKS middleware now requires an explicit allowlist of asymmetric algorithms, and it no longer derives the algorithm from untrusted JWT header values. It also explicitly rejects symmetric HS* algorithms in this context.
Before (vulnerable):
import { jwk } from 'hono/jwk'
app.use('/auth/*', jwk({
jwks_uri: 'https://example.com/.well-known/jwks.json',
// alg was optional
}))
After (patched):
import { jwk } from 'hono/jwk'
app.use('/auth/*', jwk({
jwks_uri: 'https://example.com/.well-known/jwks.json',
alg: ['RS256'], // required: explicit asymmetric algorithm allowlist
}))
(Example configuration shown in the advisory.)
Disclosure Timeline
- Discovery: 09th Dec, 2025
- First Response: 09th Dec, 2025
- Patched in: hono 4.11.4
- Advisories published: 13 Jan, 2026
References
- Advisory: GHSA-f67f-6cw9-8mq4
- Advisory: GHSA-3vhc-576x-3qv4