VYPR
Medium severity5.3NVD Advisory· Published May 28, 2026

CVE-2026-47676

CVE-2026-47676

Description

Hono is a Web application framework that provides support for any JavaScript runtime. Prior to 4.12.21, app.mount() strips the mount prefix from the incoming request path using the raw URL pathname, while route matching is performed against the percent-decoded path. This inconsistency causes the prefix to be stripped at the wrong position when the path contains percent-encoded multi-byte characters, resulting in the mounted sub-application receiving an incorrect path. This vulnerability is fixed in 4.12.21.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Hono prior to 4.12.21 mismatches raw and decoded paths in app.mount(), causing incorrect routing for percent-encoded multi-byte characters.

Vulnerability

In Hono Web application framework prior to version 4.12.21, the app.mount() function strips the mount prefix from the incoming request using the raw URL pathname, while route matching is performed against the percent-decoded path. This inconsistency causes the prefix to be stripped at the wrong position when the path contains percent-encoded multi-byte characters, leading to the mounted sub-application receiving an incorrect path [1].

Exploitation

An attacker does not require authentication or special privileges. The attack vector is network-based. To exploit the vulnerability, the attacker crafts a request URL that includes percent-encoded characters (such as encoded non-ASCII characters) in the mount prefix or subsequent path segments. When the request reaches a Hono application using app.mount(), the prefix stripping calculation uses the decoded prefix length but applies it to the raw path, producing a malformed sub-path [1].

Impact

A mounted sub-application may receive an incorrectly stripped path, causing requests to be routed to unintended handlers within the sub-application. This could lead to middleware or route handlers being bypassed or incorrectly matched due to the malformed path, potentially allowing requests to reach sub-application routes that the developer did not intend to be accessible via the mounted path [1].

Mitigation

Update to Hono version 4.12.21 or later, which contains the fix. The fix was released on 2026-05-28. No workarounds have been published in the available references [1].

AI Insight generated on May 28, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2
  • Honojs/Honoinferred2 versions
    <4.12.21+ 1 more
    • (no CPE)range: <4.12.21
    • (no CPE)range: <4.12.21

Patches

5
6cbb025ff87f

Merge commit from fork

https://github.com/honojs/honoTaku AmanoMay 19, 2026Fixed in 4.12.21via llm-release-walk
2 files changed · +35 1
  • src/hono-base.ts+1 1 modified
    @@ -364,7 +364,7 @@ class Hono<
           const pathPrefixLength = mergedPath === '/' ? 0 : mergedPath.length
           return (request) => {
             const url = new URL(request.url)
    -        url.pathname = url.pathname.slice(pathPrefixLength) || '/'
    +        url.pathname = this.getPath(request).slice(pathPrefixLength) || '/'
             return new Request(url, request)
           }
         })()
    
  • src/hono.test.ts+34 0 modified
    @@ -2685,6 +2685,40 @@ describe('app.mount()', () => {
         })
       })
     
    +  describe('With encoded paths', () => {
    +    const anotherApp = (req: Request) => new Response(getPath(req))
    +
    +    it('Should strip a decoded non-ASCII mount prefix', async () => {
    +      const app = new Hono()
    +      app.mount('/api/é', anotherApp)
    +
    +      const res = await app.request('/api/%C3%A9/hello')
    +
    +      expect(res.status).toBe(200)
    +      expect(await res.text()).toBe('/hello')
    +    })
    +
    +    it('Should preserve an encoded slash as a literal path segment after stripping the prefix', async () => {
    +      const app = new Hono()
    +      app.mount('/api/v1', anotherApp)
    +
    +      const res = await app.request('/api/v1/admin%2Fsecret')
    +
    +      expect(res.status).toBe(200)
    +      expect(await res.text()).toBe('/admin%2Fsecret')
    +    })
    +
    +    it('Should preserve encoded percent characters after stripping the prefix', async () => {
    +      const app = new Hono()
    +      app.mount('/api', anotherApp)
    +
    +      const res = await app.request('/api/foo%252Fbar')
    +
    +      expect(res.status).toBe(200)
    +      expect(await res.text()).toBe('/foo%252Fbar')
    +    })
    +  })
    +
       describe('With fetch', () => {
         const anotherApp = async (req: Request, env: {}, executionContext: ExecutionContext) => {
           const path = getPath(req)
    
905aedbc2066

Merge commit from fork

https://github.com/honojs/honoTaku AmanoMay 19, 2026Fixed in 4.12.21via llm-release-walk
2 files changed · +24 2
  • src/utils/cookie.test.ts+23 1 modified
    @@ -350,7 +350,7 @@ describe('Set cookie', () => {
         }).toThrowError('Partitioned Cookie must have Secure attributes')
       })
     
    -  it('Should throw Error cookie with domain or path containing ";", "\\r", or "\\n"', () => {
    +  it('Should throw Error cookie with domain, path, sameSite, or priority containing ";", "\\r", or "\\n"', () => {
         // domain
         expect(() => {
           serialize('great_cookie', 'banana', { domain: 'example.com;evil' })
    @@ -372,6 +372,28 @@ describe('Set cookie', () => {
         expect(() => {
           serialize('great_cookie', 'banana', { path: '/\nevil' })
         }).toThrowError('path must not contain ";", "\\r", or "\\n"')
    +
    +    // sameSite
    +    expect(() => {
    +      serialize('great_cookie', 'banana', { sameSite: 'Strict;evil' as 'Strict' })
    +    }).toThrowError('sameSite must not contain ";", "\\r", or "\\n"')
    +    expect(() => {
    +      serialize('great_cookie', 'banana', { sameSite: 'Strict\revil' as 'Strict' })
    +    }).toThrowError('sameSite must not contain ";", "\\r", or "\\n"')
    +    expect(() => {
    +      serialize('great_cookie', 'banana', { sameSite: 'Strict\nevil' as 'Strict' })
    +    }).toThrowError('sameSite must not contain ";", "\\r", or "\\n"')
    +
    +    // priority
    +    expect(() => {
    +      serialize('great_cookie', 'banana', { priority: 'High;evil' as 'High' })
    +    }).toThrowError('priority must not contain ";", "\\r", or "\\n"')
    +    expect(() => {
    +      serialize('great_cookie', 'banana', { priority: 'High\revil' as 'High' })
    +    }).toThrowError('priority must not contain ";", "\\r", or "\\n"')
    +    expect(() => {
    +      serialize('great_cookie', 'banana', { priority: 'High\nevil' as 'High' })
    +    }).toThrowError('priority must not contain ";", "\\r", or "\\n"')
       })
     
       it('Should throw Error for invalid cookie name', () => {
    
  • src/utils/cookie.ts+1 1 modified
    @@ -191,7 +191,7 @@ const _serialize = (name: string, value: string, opt: CookieOptions = {}): strin
         }
       }
     
    -  for (const key of ['domain', 'path'] as (keyof CookieOptions)[]) {
    +  for (const key of ['domain', 'path', 'sameSite', 'priority'] as (keyof CookieOptions)[]) {
         if (opt[key] && /[;\r\n]/.test(opt[key] as string)) {
           throw new Error(`${key} must not contain ";", "\\r", or "\\n"`)
         }
    
c831020fb1fa
https://github.com/honojs/honoFixed in 4.12.21via llm-release-walk
5463db273547
https://github.com/honojs/honoFixed in 4.12.21via llm-release-walk
a83ddb882e0c

4.12.21

https://github.com/honojs/honoYusuke WadaMay 19, 2026Fixed in 4.12.21via release-tag
1 file changed · +1 1
  • package.json+1 1 modified
    @@ -1,6 +1,6 @@
     {
       "name": "hono",
    -  "version": "4.12.20",
    +  "version": "4.12.21",
       "description": "Web framework built on Web Standards",
       "main": "dist/cjs/index.js",
       "type": "module",
    

Vulnerability mechanics

No source-code context for this CVE — mechanics is only generated when we can read the actual fix diff. Without that, the four sections (root cause, attack vector, affected code, fix) would be speculation rather than analysis.

References

1

News mentions

0

No linked articles in our index yet.