Summary
A flaw in Hono’s JWK/JWKS JWT verification middleware allowed the JWT header’s alg value to influence signature verification when the selected JWK did not explicitly specify an algorithm. This could enable JWT algorithm confusion and, in certain configurations, allow forged tokens to be accepted.
Details
When verifying JWTs using JWKs or a JWKS endpoint, the middleware selected the verification algorithm based on the JWK’s alg field if present, but otherwise fell back to the alg value provided in the unverified JWT header.
Because the alg field in a JWK is optional and often omitted in real-world JWKS configurations, this behavior could allow an attacker to control the algorithm used for verification. In some environments, this may lead to authentication or authorization bypass through crafted tokens.
The practical impact depends on application configuration, including which algorithms are accepted and how JWTs are used for authorization decisions.
Impact
In affected configurations, an attacker may be able to forge JWTs with attacker-controlled claims, potentially resulting in authentication or authorization bypass.
Applications that do not use the JWK/JWKS middleware, do not rely on JWT-based authentication, or explicitly restrict allowed algorithms are not affected.
Resolution
Update to the latest patched release.
Breaking change:
As part of this fix, the JWT middleware now requires the alg option to be explicitly specified. This prevents algorithm confusion by ensuring that the verification algorithm is not derived from untrusted JWT header values.
Applications upgrading must update their configuration accordingly.
Before (vulnerable configuration)
ts import { jwt } from 'hono/jwt'
app.use( '/auth/', jwt({ secret: 'it-is-very-secret', // alg was optional }) )
After (patched configuration)
ts import { jwt } from 'hono/jwt'
app.use( '/auth/', jwt({ secret: 'it-is-very-secret', alg: 'HS256', // required }) )
Summary
A flaw in Hono’s JWK/JWKS JWT verification middleware allowed the algorithm specified in the JWT header to influence signature verification when the selected JWK did not explicitly define an algorithm. This could enable JWT algorithm confusion and, in certain configurations, allow forged tokens to be accepted.
Details
When verifying JWTs using JWKs or a JWKS endpoint, the middleware selected the verification algorithm based on the JWK’s alg field if present. If the JWK did not specify an algorithm, the middleware fell back to using the alg value provided in the unverified JWT header.
Because the alg field in a JWK is optional and commonly omitted in real-world JWKS configurations, this behavior could allow an attacker to influence which algorithm is used for verification. In some environments, this may result in authentication or authorization bypass through crafted JWTs.
The practical impact depends on application configuration, including which algorithms are accepted and how JWTs are used to make authorization decisions.
Impact
In affected configurations, an attacker may be able to forge JWTs with attacker-controlled claims, potentially leading to authentication or authorization bypass.
Applications that do not use the JWK/JWKS middleware, do not rely on JWT-based authentication, or explicitly restrict allowed algorithms are not affected.
Resolution
Update to the latest patched release.
Breaking change:
The JWK/JWKS JWT verification middleware has been updated to require an explicit allowlist of asymmetric algorithms when verifying tokens. The middleware no longer derives the verification algorithm from untrusted JWT header values.
Instead, callers must explicitly specify which asymmetric algorithms are permitted, and only tokens signed with those algorithms will be accepted. This prevents JWT algorithm confusion by ensuring that algorithm selection is fully controlled by application configuration.
As part of this fix, the alg option is now required when using the JWK/JWKS middleware, and symmetric (HS) algorithms are no longer accepted in this context.
Before (vulnerable configuration)
ts import { jwk } from 'hono/jwk'
app.use( '/auth/', jwk({ jwksuri: 'https://example.com/.well-known/jwks.json', // alg was optional }) )
After (patched configuration)
ts import { jwk } from 'hono/jwk'
app.use( '/auth/', jwk({ jwksuri: 'https://example.com/.well-known/jwks.json', alg: ['RS256'], // required: explicit asymmetric algorithm allowlist }) )
Summary
When using the AWS Lambda adapter (hono/aws-lambda) behind an Application Load Balancer (ALB), the getConnInfo() function incorrectly selected the first value from the X-Forwarded-For header.
Because AWS ALB appends the real client IP address to the end of the X-Forwarded-For header, the first value can be attacker-controlled.
This could allow IP-based access control mechanisms (such as the ipRestriction middleware) to be bypassed.
Details
In ALB environments, AWS appends the actual client IP address to the end of any existing X-Forwarded-For header value. However, the previous implementation of getConnInfo() extracted the leftmost IP address:
ts address = xff.split(',')[0].trim()
If a client sent:
X-Forwarded-For: <spoofed-ip>
ALB would forward:
X-Forwarded-For: <spoofed-ip>, <real-client-ip>
Since the implementation selected the first value, the spoofed IP address was trusted. This affected applications using:
ts ipRestriction(getConnInfo, { allowList: [...] })
or any custom middleware relying on getConnInfo(c).remote.address for authorization decisions.
The issue only affects deployments using the AWS Lambda adapter behind an ALB. API Gateway (v1/v2) and Lambda Function URLs are not affected, as they use AWS-provided source IP values from requestContext.
Impact
An unauthenticated remote attacker could bypass IP-based access restrictions by supplying a crafted X-Forwarded-For header. This may allow access to resources that were intended to be restricted by IP address.
Only applications deployed behind an ALB and relying on getConnInfo() for IP-based authorization are affected.
Hono before 4.12.12 does not validate cookie names on the write path in the setCookie(), serialize(), and serializeSigned() functions, allowing invalid characters such as control characters (e.g. \r or \n) when an application passes a user-controlled cookie name. This can produce malformed Set-Cookie header values. In modern runtimes such as Node.js and Cloudflare Workers, such invalid header values are rejected and cause a runtime error before the response is sent, so header injection or response splitting could not be reproduced; the issue primarily affects correctness and robustness, resulting in runtime errors (availability) rather than confirmed header injection.
Summary
The jwt and jwk middlewares do not verify that the Authorization header value uses theBearer scheme. Any two-part header value — regardless of the scheme name in the first position — proceeds to JWT verification. A request presenting a valid JWT under a non-Bearer scheme identifier (such as Basic or Token) is authenticated identically to a correctly formed Bearer request.
Details
When processing an Authorization (or custom) header, the middleware splits the value on whitespace and uses the second token as the JWT to verify. It does not check that the first token is bearer (case-insensitively). RFC 6750 specifies that JWT bearer tokens must be presented using the Bearer scheme; other scheme identifiers carry distinct semantics and may be subject to different policies in network-layer security controls.
This discrepancy means that scheme-aware external controls — such as WAF rules, API gateways, or reverse proxies that apply policies specific to the Bearer scheme identifier — can be bypassed by presenting a valid JWT under a different scheme name.
This issue affects hono/jwt and hono/jwk middleware.
Impact
An attacker who possesses a valid JWT may present it under a non-Bearer scheme identifier and still pass middleware authentication.
This may lead to:
- Bypass of network-layer security controls that inspect or filter requests based on the authorization scheme identifier - Token reuse across authentication schemes in applications that use multiple authorization mechanisms
This issue affects applications where hono/jwt or hono/jwk authentication is combined with external controls that enforce scheme-based access policies.
Summary
The ip-restriction middleware (hono/ip-restriction) compares incoming IP addresses against configured deny and allow rules using string equality after partial normalization. Non-canonical IPv6 representations of an address already listed in a static rule — such as compressed forms, explicit-zero forms, or hex-notation IPv4-mapped addresses — do not match the normalized rule entry, causing the rule to be silently skipped.
Details
When the rule matcher is built, each configured IP rule is normalized to a canonical string form. Incoming IP addresses received at request time are then compared against those canonical strings without applying the same normalization. Because IPv6 permits multiple syntactically different representations of the same numeric address, a non-canonical form of a denied address fails the string lookup and proceeds to the CIDR check, which also finds no match for rules registered as static (no prefix length). The request is then allowed.
Affected non-canonical forms include:
- Compressed versus expanded notation (2001:db8::1 vs 2001:db8:0:0:0:0:0:1) - Hex-notation IPv4-mapped addresses (::ffff:7f00:1 vs ::ffff:127.0.0.1) - Zone identifier suffixes (e.g., fe80::1%eth0)
Additionally, invalid IP address strings provided as the remote address are not rejected and may result in unexpected allow or deny behavior.
This issue arises when applications use ipRestriction() with static (non-CIDR) rules and the IP address source can supply addresses in non-canonical IPv6 form.
Impact
A request from an IP address covered by a static deny rule may bypass the restriction if the address is presented in a non-canonical IPv6 form.
This may lead to:
- Unauthorized access to endpoints intended to be restricted to specific IP addresses - Bypass of IP-based access controls in environments where the runtime or an upstream proxy provides source addresses in a form that differs from the canonical form used in the rule configuration
This issue affects applications using hono/ip-restriction with static deny rules for IPv4 or IPv6 addresses, particularly when the source address is derived from proxy headers or custom getIP implementations that may return non-canonical forms.
Summary
app.mount() strips the mount prefix from the incoming request path using the raw URL pathname, while route matching is performed against the percent-decoded path. This inconsistency causes the prefix to be stripped at the wrong position when the path contains percent-encoded multi-byte characters, resulting in the mounted sub-application receiving an incorrect path.
Details
When app.mount(prefix, subApp) is called, Hono calculates the number of characters to strip based on the decoded mount prefix length, but then applies that slice to the raw URL pathname. When the URL contains percent-encoded characters that expand to fewer characters when decoded (such as encoded non-ASCII characters), the two representations have different lengths, so the prefix is stripped at the wrong byte offset.
As a result, the sub-application receives a path that does not correspond to the intended sub-path — it may receive a partial or garbled path instead of the expected value after the mount prefix is removed.
This issue arises when an application uses app.mount() with paths that contain percent-encoded characters, particularly when the mount prefix itself or the request path contains encoded non-ASCII characters.
Impact
A mounted sub-application may receive an incorrectly stripped path, causing requests to be routed to unintended handlers within the sub-application.
This may lead to:
- Middleware or route handlers in the sub-application being bypassed or incorrectly matched due to the malformed path - Requests reaching sub-application routes that the developer did not intend to be accessible via the mounted path
This issue affects applications that use app.mount() where the request URL may contain percent-encoded characters in the mount prefix or subsequent path segments.
Summary
The serialize() function in hono/cookie validates domain and path options against characters that corrupt Set-Cookie header syntax (;, \r, \n), but does not apply the same validation to sameSite and priority. An application that passes user-controlled input into either option may produce a Set-Cookie response header containing attacker-chosen additional attributes.
Details
When constructing a Set-Cookie header value, serialize() appends the sameSite and priority option values directly into the output string after a presentation-only transformation (capitalizing the first character). Although the TypeScript type signature constrains these options to specific string literals, that constraint is not enforced at runtime; any string value, including one containing ; or line-feed characters, passes through unchanged.
The validation guard that rejects ;, \r, and \n from domain and path is not applied to sameSite or priority. An application that passes a request-derived value to either option therefore provides an injection point into the header line.
This issue arises when an application passes user-controlled input to the sameSite or priority option of setCookie() or serialize().
Impact
An attacker who can control the sameSite or priority option value may inject additional attributes into a Set-Cookie response header.
This may lead to:
- Cookie attribute injection — overriding Domain, Path, HttpOnly, Secure, or Max-Age for the affected cookie - HTTP response header injection on runtimes that do not strictly validate header values, enabling a second attacker-controlled Set-Cookie header in the same response
This issue affects applications that pass user-derived input into the sameSite or priority option of hono/cookie serialization functions.
hono before 4.12.14 contains an html injection vulnerability in jsx server-side rendering that allows attackers to inject unintended html by using malformed attribute names. Attackers can craft specially crafted attribute keys containing characters like quotes or angle brackets to break html tag boundaries and inject arbitrary attributes or elements.
Summary
A Cross-Site Scripting (XSS) vulnerability exists in the ErrorBoundary component of the hono/jsx library. Under certain usage patterns, untrusted user-controlled strings may be rendered as raw HTML, allowing arbitrary script execution in the victim's browser.
Details
The issue is in the ErrorBoundary component (src/jsx/components.ts). ErrorBoundary previously forced certain rendered output paths to be treated as raw HTML, bypassing the library's default escaping behavior. This could result in unescaped rendering when developers pass user-controlled strings directly as children, or when fallbackRender returns user-controlled strings (for example, reflecting error messages that contain attacker input).
This vulnerability is only exploitable when an application renders untrusted user input within ErrorBoundary without appropriate escaping or sanitization.
Impact
Successful exploitation may allow attackers to execute arbitrary JavaScript in the victim’s browser (reflected XSS). Depending on the application context, this can lead to actions such as session compromise, data exfiltration, or performing unauthorized actions as the victim.
Affected Components
hono/jsx: ErrorBoundary component