Jun 4, 2026·6 min read·21 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 critical parser differential and host confusion vulnerability (CVE-2026-76172) exists in fast-uri, a dependency-free URI validation and normalization library for Node.js. This vulnerability stems from improper validation of the URI scheme component after decoding percent-encoded characters using the legacy global unescape() function. This allows structural characters such as path delimiters and control characters to be written raw into the output stream during serialization, causing host confusion, Server-Side Request Forgery (SSRF), or HTTP response splitting downstream.
A double-decoding vulnerability in the fast-uri package allows unauthenticated remote attackers to bypass host-policy validation and conduct Server-Side Request Forgery (SSRF) attacks by submitting nested percent-encoded URI strings.
A critical parser differential vulnerability in the Node.js fast-uri library allows unauthenticated remote attackers to bypass address-validation filters and perform Server-Side Request Forgery (SSRF). The library fails to validate complete IPv6 grammar inside bracketed literals, silently truncating invalid trailing characters and normalising malformed hosts into valid loopback or private addresses.
A host confusion vulnerability exists in the fast-uri Node.js library when parsing scheme-relative URI references. Due to inconsistent domain name canonicalization, applications validating resolved hosts can be bypassed by downstream WHATWG-compliant parsers, facilitating Server-Side Request Forgery (SSRF).
Sulu CMS, an open-source PHP content management system based on the Symfony framework, is affected by an Insecure Direct Object Reference (IDOR) vulnerability within its media relocation API. Authenticated users with restricted edit permissions can relocate media out of secure, unauthorized collections into folders they control, bypassing access controls entirely. This security issue is tracked under CVE-2026-82395 and GHSA-h6cx-gjxx-v25c.
An incomplete sanitization fix for CVE-2026-35536 in Tornado allowed cookie attribute injection. The framework's validation loop checked lowercase keyword arguments but neglected legacy case-insensitive parameters passed through arbitrary keyword arguments, which Python's underlying library parses case-insensitively.