v4.13.5
This release includes fixes for the following security issues:
Query parser reads parameters after the URL fragment, causing cache-key and proxy interpretation differentials
Affects: Cache Middleware and applications behind a proxy, WAF, or logging layer that inspects query strings. Fixes query parsing that did not stop at the URL fragment, so a ? after a # was treated as the start of a query string and the application could read parameters that the other component never saw. GHSA-crvj-82cr-hjcx
Affects: toSSG() for Static Site Generation. Fixes a path normalization gap where consecutive parent-directory segments in ssgParams values were not fully collapsed, bypassing the containment check added in 4.12.12. GHSA-gqvv-2mrq-wpjv
Affects: parseBody() when dot-notation parsing is enabled. Fixes unbounded expansion of dot-separated field names, where a small request body could allocate a disproportionately large object graph and concurrent requests could exhaust the heap. GHSA-g6gw-c38x-mqfc
Users who use Cache Middleware, deploy behind a proxy or WAF that inspects query strings, use Static Site Generation, or use parseBody({ dot: true }) are strongly encouraged to upgrade to this version.
v4.13.4
- fix(request): handle params on unmatched requests in https://github.com/honojs/hono/pull/5268
- fix(jsx/dom): execute previous ref cleanup when ref prop changes on re-render in https://github.com/honojs/hono/pull/5264
- fix(reg-exp-router): associate wildcard middleware with matching routes in https://github.com/honojs/hono/pull/5266
- perf(router): share null object creation in https://github.com/honojs/hono/pull/5267
- fix(etag): match If-None-Match tags with optional whitespace before the comma in https://github.com/honojs/hono/pull/5222
- fix(client): skip undefined header and cookie values in https://github.com/honojs/hono/pull/5244
- fix(client): skip an undefined entry inside a query array in https://github.com/honojs/hono/pull/5272
- fix(client): skip an undefined entry inside a form array in https://github.com/honojs/hono/pull/5280
- fix(client): support custom buildSearchParams and filter undefined query in $ws() bin https://github.com/honojs/hono/pull/5256
- fix(accepts): support wildcard media types and specificity ordering in defaultMatch in https://github.com/honojs/hono/pull/5255
- fix(client): omit empty query delimiter in https://github.com/honojs/hono/pull/5283
- fix(request): drop stale content length for cloned FormData in https://github.com/honojs/hono/pull/5282
- fix(request): serialize cached JSON body in cloneRawRequest in https://github.com/honojs/hono/pull/5288
- fix(cookie): allow parsing signed cookies with empty string values in https://github.com/honojs/hono/pull/5246
- fix(utils/stream): do not let abort listeners crash abort() in https://github.com/honojs/hono/pull/5274
Full Changelog: https://github.com/honojs/hono/compare/v4.13.3...v4.13.4
v4.13.3
- fix(client): prevent URL corruption when replaceUrlParam contains $ replacement tokens in https://github.com/honojs/hono/pull/5227
- fix(etag): copy pending stream bytes in https://github.com/honojs/hono/pull/5239
- fix(etag): avoid skipping headers when filtering 304 response headers in https://github.com/honojs/hono/pull/5234
- fix(cors): append Origin to Vary header on OPTIONS preflight in https://github.com/honojs/hono/pull/5235
- docs(context): add custom headers append option example to Context JSDoc in https://github.com/honojs/hono/pull/5248
- fix(trie-router): match suffix wildcard routes in https://github.com/honojs/hono/pull/5236
- fix(pattern-router/linear-router): prevent prefix overmatch on wildcard routes in https://github.com/honojs/hono/pull/5252
- fix(csrf): exempt OPTIONS request from CSRF validation in https://github.com/honojs/hono/pull/5250
- fix(utils/ipaddr): avoid truncation on embedded IPv4 addresses in expand IPv6 in https://github.com/honojs/hono/pull/5247
- feat(pretty-json): support structured JSON content-types (+json) in https://github.com/honojs/hono/pull/5226
Full Changelog: https://github.com/honojs/hono/compare/v4.13.2...v4.13.3
v4.13.2
- fix(secure-headers): output standard empty parentheses () instead of none for disabled Permissions-Policy directives in https://github.com/honojs/hono/pull/5197
- fix(jsx): render async children of document metadata tags instead of [object Promise] in https://github.com/honojs/hono/pull/5204
- fix(etag): resolve incorrect incremental hashing for chunked responses in https://github.com/honojs/hono/pull/5199
- fix(client): serialize multiple cookies correctly in https://github.com/honojs/hono/pull/5202
- fix(etag): stabilize digest across stream chunks in https://github.com/honojs/hono/pull/5205
- fix(url): strip trailing question mark correctly for optional params with regex quantifiers in https://github.com/honojs/hono/pull/5209
- perf(cors): pre-join static array header options during initialization in https://github.com/honojs/hono/pull/5210
- fix(client): send falsy JSON bodies in https://github.com/honojs/hono/pull/5215
- feat(secure-headers): add missing W3C Permissions-Policy directives in https://github.com/honojs/hono/pull/5214
Full Changelog: https://github.com/honojs/hono/compare/v4.13.1...v4.13.2
v4.13.1
- fix(trie-router): count every slash a pattern consumes by @Jaybhade in https://github.com/honojs/hono/pull/5189
- fix(utils/stream): re-acquire writer lock when pipe() throws by @Sriharsha-dev369 in https://github.com/honojs/hono/pull/4988
- fix(etag): skip unsafe methods or error responses on non-* case by @na-trium-144 in https://github.com/honojs/hono/pull/5196
- @Jaybhade made their first contribution in https://github.com/honojs/hono/pull/5189
- @Sriharsha-dev369 made their first contribution in https://github.com/honojs/hono/pull/4988
Full Changelog: https://github.com/honojs/hono/compare/v4.13.0...v4.13.1
v4.13.0
Hono v4.13.0 is now available!
The highlight of this release is performance: a batch of low-level optimizations makes the core request/response path significantly faster — up to 1.25x on common routes in our benchmark. This release also adds first-class support for the HTTP QUERY method, defined in RFC 10008, a new Method Not Allowed middleware, and more.
This release includes a series of small optimizations: skipping unnecessary Headers allocations, replacing regex tests with indexOf, allocating internal state lazily, and more.
Here is benchmarks/fetch comparing v4.12 and v4.13 (ROUNDS=5 ./compare.sh, Bun 1.4.0, Apple Silicon — each measurement runs in a fresh process, and the variant order is reversed every round to avoid warm-up bias):
| Benchmark | v4.12 | v4.13 | Speedup |
|---|---|---|---|
ping — GET / |
165.83 ns | 163.99 ns | 1.01x |
query — GET /id/1?name=bun |
674.40 ns | 616.99 ns | 1.09x |
json — GET /user |
528.99 ns | 422.44 ns | 1.25x |
body — POST /json |
1.16 µs | 1.00 µs | 1.15x |
The individual changes:
- perf(context): iterate the header record with
for..inhttps://github.com/honojs/hono/pull/5118 - perf(url): replace regex tests with
indexOfhttps://github.com/honojs/hono/pull/5121 - perf(context): skip
Headerscreation when there are no headers to merge https://github.com/honojs/hono/pull/5122 - perf(urls): refactor
tryDecodeURIComponenthttps://github.com/honojs/hono/pull/5158 - perf(request): allocate
#validatedDatalazily https://github.com/honojs/hono/pull/5175 - perf(request): probe the body cache without allocating https://github.com/honojs/hono/pull/5176
In addition, the RegExpRouter rewrite described below makes route registration plus the first match roughly 20% faster.
Thanks @kibertoad for the contributions!
The QUERY method — a safe, idempotent method that carries a request body — is now a first-class citizen in Hono. You can define QUERY handlers with app.query():
const app = new Hono()
app.query('/search', async (c) => {
const conditions = await c.req.json()
return c.json(await search(conditions))
})
Thanks @shellhaki!
The built-in middleware has been updated to handle QUERY requests properly:
The Cache Middleware now caches QUERY responses. Following RFC 10008 Section 2.7, the cache key incorporates a SHA-256 digest of the request content and its representation metadata, so different query bodies are cached separately:
app.query(
'/search',
cache({
cacheName: 'search-cache',
cacheControl: 'max-age=3600',
})
)
Note: To support this, the internal cache key format has changed for all methods, including GET. Cached entries are now stored under an internal URL of the form /.hono/cache?__hono_cache_key=.... If you purge cache entries by URL outside of the middleware (e.g. calling caches.delete() with the original request URL), you will need to update that logic. Existing cache entries stored with the old format will simply be re-fetched.
The ETag Middleware now handles conditional requests for QUERY, returning 304 Not Modified when If-None-Match matches.
The CORS Middleware now includes QUERY in the default Access-Control-Allow-Methods, which is now GET, HEAD, PUT, POST, DELETE, PATCH, QUERY. If you specify allowMethods explicitly, nothing changes for you.
Thanks @usualoma and @Cherry!
The new Method Not Allowed Middleware returns a 405 Method Not Allowed response with a proper Allow header when the request path matches a registered route but the method does not:
import { methodNotAllowed } from 'hono/method-not-allowed'
const app = new Hono()
app.use(methodNotAllowed({ app }))
app.get('/hello', (c) => c.text('Hello!'))
app.post('/hello', (c) => c.text('Posted!'))
// PUT /hello -> 405 Method Not Allowed
// Allow: GET, HEAD, POST
You can customize the response with the onMethodNotAllowed option:
app.use(
methodNotAllowed({
app,
onMethodNotAllowed: (c, methods) =>
c.json({ error: 'Method Not Allowed' }, 405, { Allow: methods.join(', ') }),
})
)
Thanks @usualoma!
The RegExpRouter now detects unsupported path combinations when routes are registered, instead of at the first matching request. This means misconfigured routes fail fast at startup rather than at runtime. As a bonus, registration plus the first match is roughly 20% faster.
Thanks @usualoma!
hono/utils/headershas been synced with the IANA HTTP Field Name Registry, adding newly registered fields such asAccept-Query. Thanks @akahoshi1421!- The JWT and JWK middleware now accept a
realmoption for theWWW-Authenticatechallenge on401responses, and challenge values are properly escaped. Thanks @arhxam! - JSX:
useRefandRefObjectare now aligned with React 19. Note that this is a type-level change —RefObject<T>is now{ current: T }, so type a nullable ref asRefObject<T | null>, and passuseRef(undefined)instead ofuseRef(). Thanks @ashunar0! - JSX: a function component can now return an array of children without throwing during server-side rendering. Thanks @natsuki-engr!
- The Compress Middleware now sets
Vary: Accept-Encodingon negotiated responses. Thanks @arhxam!
- perf(hono-base): avoid rest parameter in
fetchby @yusukebe in https://github.com/honojs/hono/pull/5113 - perf(context): iterate the header record with for..in by @yusukebe in https://github.com/honojs/hono/pull/5118
- perf(url/request): replace regex tests with
indexOfby @yusukebe in https://github.com/honojs/hono/pull/5121 - perf(context): skip Headers creation when there are no headers to merge by @yusukebe in https://github.com/honojs/hono/pull/5122
- perf(urls): refactor
tryDecodeURIComponentby @yusukebe in https://github.com/honojs/hono/pull/5158 - chore(benchmarks): correct src path on Windows, add json and middleware cases by @kibertoad in https://github.com/honojs/hono/pull/5173
- perf(context): drop the throwaway
envfield initializer by @kibertoad in https://github.com/honojs/hono/pull/5174 - perf(request): allocate
#validatedDatalazily by @kibertoad in https://github.com/honojs/hono/pull/5175 - perf(request): probe the body cache without allocating by @kibertoad in https://github.com/honojs/hono/pull/5176
- chore(benchmarks): stabilize measurements by forcing mitata batching by @yusukebe in https://github.com/honojs/hono/pull/5183
- perf(hono-base): restore the rest parameter in
fetchby @yusukebe in https://github.com/honojs/hono/pull/5184 - perf(context): restore the
envfield initializer by @yusukebe in https://github.com/honojs/hono/pull/5186 - feat: add first-class QUERY method support by @shellhaki in https://github.com/honojs/hono/pull/5070
- feat(etag): support conditional requests for the QUERY method by @Cherry in https://github.com/honojs/hono/pull/5111
- feat(cors): allow QUERY by default as a first-class method by @usualoma in https://github.com/honojs/hono/pull/5115
- feat(cache): add first-class support for QUERY requests by @usualoma in https://github.com/honojs/hono/pull/5119
- feat(jsx): add React-compatible overloads to useRef by @ashunar0 in https://github.com/honojs/hono/pull/5063
- feat(middleware): add method-not-allowed middleware by @usualoma in https://github.com/honojs/hono/pull/5132
- feat(jwt,jwk): add a configurable WWW-Authenticate realm by @arhxam in https://github.com/honojs/hono/pull/5141
- feat(utils/headers): sync HTTP field types with the IANA registry by @akahoshi1421 in https://github.com/honojs/hono/pull/5153
- fix(jsx): allow a function component to return an array by @natsuki-engr in https://github.com/honojs/hono/pull/5179
- feat(reg-exp-router): throw UnsupportedPathError during route registration by @usualoma in https://github.com/honojs/hono/pull/5171
- fix(compress): set Vary: Accept-Encoding on negotiated responses by @arhxam in https://github.com/honojs/hono/pull/5137
Full Changelog: https://github.com/honojs/hono/compare/v4.12.34...v4.13.0
Thank you to all contributors!
v4.12.34
This release includes fixes for the following security issues:
Affects: hono/jsx (server-side rendering). Fixes memo() reusing a retained render result across requests when props compare equal, where a component reading request-scoped values from ambient context — useContext(), useRequestContext(), or getContext() — could serve HTML rendered for another user's request, disclosing account data or request-scoped secrets such as CSRF tokens. GHSA-f23p-vx2j-j53r
Affects: hono/cors. Fixes a whitespace-tolerant regular expression with quadratic backtracking used to parse the Access-Control-Request-Headers preflight header when allowHeaders is not configured (the default), where a single preflight request carrying a long whitespace run could consume seconds of CPU and stall request processing. GHSA-8j4g-w8fx-2239
Affects: hono/language. Fixes quadratic string processing in language-tag normalization, where a crafted language tag with a large number of hyphen-separated subtags — supplied via a query parameter, cookie, or Accept-Language header — could cause excessive CPU consumption and block the event loop. GHSA-54fx-42gc-7vw4
Affects: hono/proxy. Fixes proxy() forwarding response headers that the origin's Connection header designates as connection-scoped, where headers intended only for the immediate peer — per RFC 9110 Section 7.6.1 — could be exposed to clients, disclosing connection-scoped or internal metadata. GHSA-79qm-7rj5-m7r9
Users who use hono/jsx for server-side rendering, hono/cors, hono/language, or hono/proxy are strongly encouraged to upgrade to this version.
v4.12.33
- fix(cookie): relax name validation when parsing Cookie header in https://github.com/honojs/hono/pull/5164
- chore: bump
@hono/node-serverin https://github.com/honojs/hono/pull/5167 - fix(jsx): handle useSyncExternalStore subscription and snapshot changes in https://github.com/honojs/hono/pull/5166
- chore: remove undici in favor of global fetch in https://github.com/honojs/hono/pull/5168
Full Changelog: https://github.com/honojs/hono/compare/v4.12.32...v4.12.33
v4.12.32
- ci: enable reports for type & bundle size check in https://github.com/honojs/hono/pull/5148
- fix(aws-lambda): add jwt and lambda authorizer types for API Gateway v2 in https://github.com/honojs/hono/pull/5142
- fix(sse): emit empty id field to reset Last-Event-ID in https://github.com/honojs/hono/pull/5138
- test(cloudflare-workers): add coverage for onClose, onError, send, and close in Cloudflare Workers websocket adapter in https://github.com/honojs/hono/pull/5145
- fix: use
Object.create(null)when parsing query, headers, and params in https://github.com/honojs/hono/pull/5161 - fix(secure-headers): keep CSP callbacks scoped to their header in https://github.com/honojs/hono/pull/5147
Full Changelog: https://github.com/honojs/hono/compare/v4.12.31...v4.12.32
v4.12.31
- test(context): assert case-insensitive header names in response helpers by @yusukebe in https://github.com/honojs/hono/pull/5116
- chore(benchmark): add app.fetch() overhead benchmark by @yusukebe in https://github.com/honojs/hono/pull/5117
- refactor(aws-lambada): remove FIXME in
@ts-expect-errorby @yusukebe in https://github.com/honojs/hono/pull/5130 - fix(utils/body): reuse cached formData in
parseBody()by @yusukebe in https://github.com/honojs/hono/pull/5131 - fix(request): fix multipart boundary mismatch in
cloneRawRequestby @yusukebe in https://github.com/honojs/hono/pull/5133 - fix(sse): emit retry feild when retry is
0by @yusukebe in https://github.com/honojs/hono/pull/5135 - test(validator): fix misspelled identifier in transform type test by @yusukebe in https://github.com/honojs/hono/pull/5136
Full Changelog: https://github.com/honojs/hono/compare/v4.12.30...v4.12.31