Bump hono to >= 4.12.34 (CVE-2026-69207, ReDoS in CORS middleware)
What & why
pnpm-lock.yaml resolves hono to 4.12.30 for apps/api and apps/proxy.
That version is affected by CVE-2026-69207 / GHSA-8j4g-w8fx-2239 ("ReDoS in
CORS middleware via Access-Control-Request-Headers"), fixed in 4.12.34.
Following your SECURITY.md ("Vulnerabilities in third-party dependencies that
are already publicly known — open a regular issue or PR to bump the dependency
instead"), this is a public issue rather than a private report.
Reachability in this codebase
The vulnerable path is only reached when a cors() call has no allowHeaders
set, so Hono reflects and parses the request's Access-Control-Request-Headers.
I checked all six cors() calls in the repo:
| Location |
allowHeaders set? |
apps/api/src/index.ts:244 |
yes |
apps/api/src/index.ts:254 |
yes |
apps/api/src/index.ts:263 (/.well-known/*) |
no |
apps/api/src/index.ts:271 |
yes |
apps/api/src/index.ts:284 |
yes |
apps/api/src/request-body-limits.ts:37 |
yes |
apps/proxy/src/index.ts:237 |
yes |
The /.well-known/* block sets only origin: "*" and allowMethods, so it
falls back to Hono's default allowHeaders: [] and hits the quadratic split
requestHeaders.split(/\s*,\s*/).
This is reachable unauthenticated: cors() answers the OPTIONS preflight
itself and never calls next(), so no route under /.well-known/ even needs to
exist (there are some anyway, at apps/api/src/mcp/oauth.ts:70 and :79).
Rough timing of the split alone on Node, using a header value made of
whitespace: 5,000 chars → 15 ms, 20,000 → 246 ms, 40,000 → 993 ms, 80,000 →
3,918 ms, cleanly quadratic. At Node's default 16 KB header limit, one request blocks
the event loop for roughly 150 ms, so a handful of requests per second is enough
to saturate an API instance. This is the realistic-DoS case your SECURITY.md
distinguishes from unrealistic traffic volumes, so flagging it explicitly.
Two things to change
- Bump
hono to >= 4.12.34 (current is 4.13.x) in apps/api/package.json
and apps/proxy/package.json.
- Also update the pinned override.
package.json pins
"@modelcontextprotocol/sdk>hono": "4.12.30" in pnpm.overrides. A normal
pnpm update raises the app ranges but leaves that copy on the vulnerable
version, so the override has to move to 4.12.34 (or higher) as well.
As defense in depth it is also worth giving the /.well-known/* block an
explicit allowHeaders, so the reflect-and-parse path is not taken regardless
of the Hono version.
How to test
A PR with the fix is attached. It bumps both app ranges and the pinned override
to ^4.12.34 (pnpm resolves that to 4.13.1), regenerates the lockfile, and adds
an explicit allowHeaders to the /.well-known/* block. Happy to adjust the
version or drop the defense-in-depth part if you'd rather keep the change
minimal.
AI assistance
Used AI to scan the dependency tree and locate the reachable cors() call; the
CVE match, the reachability table, and the override note were verified by hand
against pnpm-lock.yaml and the GHSA advisory.
Bump hono to >= 4.12.34 (CVE-2026-69207, ReDoS in CORS middleware)
What & why
pnpm-lock.yamlresolveshonoto 4.12.30 forapps/apiandapps/proxy.That version is affected by CVE-2026-69207 / GHSA-8j4g-w8fx-2239 ("ReDoS in
CORS middleware via
Access-Control-Request-Headers"), fixed in 4.12.34.Following your SECURITY.md ("Vulnerabilities in third-party dependencies that
are already publicly known — open a regular issue or PR to bump the dependency
instead"), this is a public issue rather than a private report.
Reachability in this codebase
The vulnerable path is only reached when a
cors()call has noallowHeadersset, so Hono reflects and parses the request's
Access-Control-Request-Headers.I checked all six
cors()calls in the repo:allowHeadersset?apps/api/src/index.ts:244apps/api/src/index.ts:254apps/api/src/index.ts:263(/.well-known/*)apps/api/src/index.ts:271apps/api/src/index.ts:284apps/api/src/request-body-limits.ts:37apps/proxy/src/index.ts:237The
/.well-known/*block sets onlyorigin: "*"andallowMethods, so itfalls back to Hono's default
allowHeaders: []and hits the quadratic splitrequestHeaders.split(/\s*,\s*/).This is reachable unauthenticated:
cors()answers theOPTIONSpreflightitself and never calls
next(), so no route under/.well-known/even needs toexist (there are some anyway, at
apps/api/src/mcp/oauth.ts:70and:79).Rough timing of the split alone on Node, using a header value made of
whitespace: 5,000 chars → 15 ms, 20,000 → 246 ms, 40,000 → 993 ms, 80,000 →
3,918 ms, cleanly quadratic. At Node's default 16 KB header limit, one request blocks
the event loop for roughly 150 ms, so a handful of requests per second is enough
to saturate an API instance. This is the realistic-DoS case your SECURITY.md
distinguishes from unrealistic traffic volumes, so flagging it explicitly.
Two things to change
honoto>= 4.12.34(current is 4.13.x) inapps/api/package.jsonand
apps/proxy/package.json.package.jsonpins"@modelcontextprotocol/sdk>hono": "4.12.30"inpnpm.overrides. A normalpnpm updateraises the app ranges but leaves that copy on the vulnerableversion, so the override has to move to
4.12.34(or higher) as well.As defense in depth it is also worth giving the
/.well-known/*block anexplicit
allowHeaders, so the reflect-and-parse path is not taken regardlessof the Hono version.
How to test
pnpm why honoshows no remaining 4.12.30 resolution after the bumppnpm typecheckandpnpm lintpassA PR with the fix is attached. It bumps both app ranges and the pinned override
to
^4.12.34(pnpm resolves that to 4.13.1), regenerates the lockfile, and addsan explicit
allowHeadersto the/.well-known/*block. Happy to adjust theversion or drop the defense-in-depth part if you'd rather keep the change
minimal.
AI assistance
Used AI to scan the dependency tree and locate the reachable
cors()call; theCVE match, the reachability table, and the override note were verified by hand
against
pnpm-lock.yamland the GHSA advisory.