Jun 4, 2026·6 min read·43 visits
An inconsistency between decoded prefix matching and raw path-slicing in Hono's app.mount() causes malformed path propagation and routing failures when processing percent-encoded multi-byte URI characters.
A path parsing and normalization inconsistency vulnerability exists in the Hono web framework prior to version 4.12.21. When hosting sub-applications via the app.mount() routing interface, Hono calculates the routing path prefix length on a percent-decoded representation of the URI but executes the path-slicing offset on the raw, percent-encoded string. This discrepancy results in malformed request paths being dispatched to mounted sub-applications, potentially leading to route bypasses, route confusion, and application-level Denial of Service.
The Hono web framework provides a feature via the app.mount() method that enables developers to attach independent sub-applications or custom HTTP fetch handlers to specific path prefixes within a parent application. This architecture relies on a routing separation boundary where the parent router handles the initial route matching and subsequently delegates the request execution downstream.
To forward the request accurately, the parent application must strip the matching base path prefix from the incoming URI before invoking the sub-application handler. This ensures that the sub-application only receives the sub-path matching its internal route definitions.
Prior to version 4.12.21, a severe parsing discrepancy existed between the prefix matching phase and the prefix stripping phase. While matching was calculated using the normalized, percent-decoded representation of the URL, the stripping phase applied string slicing parameters directly to the raw, percent-encoded request pathname.
This discrepancy systematically breaks routing logic when the mount path or the incoming URI contains percent-encoded multi-byte UTF-8 characters. The mismatch between the decoded character length and the raw encoded byte length results in truncated or corrupted path segments being forwarded to the sub-application context.
The fundamental flaw lies in how the routing logic computes and applies the offset index for slicing the mount prefix. In JavaScript, string lengths are determined by the number of UTF-16 code units. A percent-decoded multi-byte character, such as the UTF-8 character 'é', resolves to a single code unit with a string length of one.
When a client submits an HTTP request containing a percent-encoded sequence, such as %C3%A9 (the URL-encoded representation of 'é'), the raw string length of this sequence is six. During the initial matching phase, Hono correctly normalizes the incoming path, permitting the route evaluator to recognize and match the decoded path prefix.
However, during the request propagation phase, Hono determined the slice offset by reading the .length property of the decoded path prefix and applied this numerical index directly to the un-decoded url.pathname string. Because the raw percent-encoded string is longer than its decoded counterpart, the slice operation occurs prematurely.
As a direct result of this offset misalignment, the sliced path includes leftover fragments of the percent-encoded sequence. The malformed path is then passed to the sub-application, which fails to match any valid route handlers, culminating in unexpected routing states or failure conditions.
The source code of Hono prior to version 4.12.21 highlights the implementation of the vulnerable handler construction within the app.mount() pipeline. The calculations for pathPrefixLength and the subsequent modification of the pathname property illustrate the flawed assumptions.
// VULNERABLE CODE (hono-base.ts prior to v4.12.21)
const pathPrefixLength = mergedPath === '/' ? 0 : mergedPath.length
return (request) => {
const url = new URL(request.url)
// url.pathname contains the raw, percent-encoded path
// pathPrefixLength is calculated based on the decoded mergedPath
url.pathname = url.pathname.slice(pathPrefixLength) || '/'
return new Request(url, request)
}When a request for /api/%C3%A9/hello is routed through a sub-application mounted at /api/é, the decoded length of /api/é is calculated as 7. Slicing the raw path /api/%C3%A9/hello at index 7 removes only the prefix /api/%C and leaves 3%A9/hello intact. This malformed string becomes the new request pathname.
To remediate this issue, the patch modifies the handler to retrieve the decoded path using the internal getPath(request) method before attempting the slice. This ensures that the length subtraction occurs on a text representation that is structurally equivalent to the matched prefix.
// PATCHED CODE (hono-base.ts in v4.12.21)
const pathPrefixLength = mergedPath === '/' ? 0 : mergedPath.length
return (request) => {
const url = new URL(request.url)
// Both the calculation and the slice are now performed on normalized data
url.pathname = this.getPath(request).slice(pathPrefixLength) || '/'
return new Request(url, request)
}Exploiting this vulnerability does not require specialized tools and can be accomplished via standard HTTP clients. An attacker target must have a sub-application mounted on a prefix containing multi-byte characters or special characters that undergo normalization changes during URL decoding.
To construct a reproduction, consider a sub-application defining a sensitive route /hello mounted on the parent application at /api/é. Under normal operations, a request directed to /api/%C3%A9/hello would match the sub-application's /hello handler.
Due to the slicing bug, the path forwarded to the sub-application is evaluated as /3%A9/hello. Because this path does not exist in the routing registry, the sub-application returns a 404 error, creating an immediate Denial of Service for that functional route.
If the sub-application implements wildcard handlers (/*) or fallback routes designed to handle catch-all logic, these handlers will execute instead of the intended endpoints. An attacker can manipulate the percent-encoding in the prefix to craft predictable arbitrary path inputs to the sub-application, bypassing intermediate security filters.
The impact of this vulnerability is classified as Medium, with a CVSS v3.1 score of 5.3. The primary consequences involve integrity and availability degradation of application routing mechanisms.
In microservice architectures or multi-tenant cloud worker configurations where Hono mounts sub-applications to isolate tenants or functional areas, route confusion represents a potential security bypass. An attacker can manipulate requests to escape expected prefix scopes or access fallback routes that bypass token verification routines placed on explicit paths.
Additionally, applications serving legacy internationalized paths or relying on non-ASCII route prefixes will suffer persistent Denial of Service states. Any standard browser requests containing automatic percent-encoding of Unicode characters in the path prefix will fail to resolve inside the sub-application.
No instances of exploitation in the wild have been observed. The vulnerability is not currently listed in the CISA Known Exploited Vulnerabilities catalog, and its low EPSS score reflects its specialized exploit requirements.
The primary remediation strategy is upgrading the Hono framework dependency to version 4.12.21 or later. The patch forces uniform use of the internal path resolver, eliminating the offset length discrepancy.
Review of the patch reveals a critical edge case regarding the manual definition of mount paths. If developers configure the mount prefix using percent-encoded literals directly (e.g., app.mount('/api/%C3%A9', subApp)), the mergedPath variable length calculation will measure the raw length (10), while the patched logic will apply this index to the decoded path (length 12), resulting in over-slicing and routing failures.
Furthermore, the getPath utility invokes decodeURI internally to handle normalization. If an attacker submits a malformed percent-encoded sequence (such as /% or /%G1) in the path prefix, decodeURI throws a native URIError exception.
If the Hono instance lacks a comprehensive global error handling middleware, this unhandled exception will propagate to the Node.js or serverless host runtime. This behavior can result in unexpected process terminations or worker crashes, exposing an alternative vector for Denial of Service attacks.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
hono honojs | < 4.12.21 | 4.12.21 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-444 (Inconsistent Interpretation of HTTP Requests) |
| Attack Vector | Network (AV:N) |
| CVSS Severity | 5.3 Medium |
| Exploit Status | Proof of Concept available in test suites |
| KEV Status | Not listed |
| Ransomware Use | No known usage |
The application calculates string length offsets using a percent-decoded path representation but applies the resulting offset slice to the raw percent-encoded URI string, causing parsing misalignment.
A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.
An out-of-bounds write vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio allows unauthenticated remote attackers to execute arbitrary code via crafted pixel-shader bytecode or auto-converted clipboard payloads.
ASP.NET Core contains a thread deadlock vulnerability (CWE-833) that allows an unauthenticated remote attacker to cause a denial of service over the network by exhausting server thread pool resources.
CVE-2026-70035 is a high-severity Remote Code Execution (RCE) vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio caused by improper handling during the deserialization of untrusted data (CWE-502). An unauthenticated attacker can execute arbitrary code within the context of the affected process by delivering a crafted serialized payload.
An elevation of privilege vulnerability exists in ASP.NET Core and Microsoft Visual Studio due to improper synchronization during concurrent thread execution. Authenticated remote attackers with low privileges can exploit a timing window to manipulate shared resources and assume higher-level execution contexts.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.