Hono: `mount()` and `app.mount()` can forward a path that bypasses middleware scoped inside the mount prefix
🔗 CVE IDs covered (1)
📋 Description
Summary
mount() and app.mount() remove the mount prefix from the request path and forward the rest to the mounted application. Two mistakes in that step let a crafted request reach a route of the mounted application that the outer application protects with path-scoped middleware, such as an authentication check on /app/admin/*. The outer application routes on the original path, so the middleware does not run.
Details
- Dynamic prefix (all affected versions): for a mount such as
/api/:tenant/*, the prefix was removed by the length of the route pattern, not of the matched prefix. A request with a longer or shorter first segment is cut in the middle, so/api/a/xxxxx/admin/secretreaches the mounted application as/admin/secret. - Re-normalization (since 4.12.21): the forwarded path was built from the decoded request path and assigned to
url.pathname, which turns a decoded backslash into/and collapses.../app/public%5C..%5Cadmin/secretreaches the mounted application as/admin/secret.
The fix removes the prefix segment by segment from the raw pathname, using the matched parameter values for its length. Route patterns that cannot be handled safely now throw: duplicate parameter names and a wildcard inside the last segment such as /assets*. A trailing slash in an app.mount() prefix no longer removes an extra segment.
Impact
An unauthenticated client can reach a route of a mounted application that the outer application protects with path-scoped middleware.
This affects applications that use mount() or app.mount() and rely on middleware registered on a sub-path inside the mount prefix for authentication or authorization.
Workarounds
Register the authentication middleware inside the mounted application.
🎯 Affected products1
- npm/hono:< 4.13.16