Skip to content

RegExpRouter: wildcard routes don't match paths containing an encoded line terminator (%0A, %0D) #5345

Description

@adeighton

What version of Hono are you using?

4.13.7

What runtime/platform is your app running on? (with version if possible)

Node.js v24.20.0 with @hono/node-server, but the reproduction below uses app.request(), so it looks runtime-independent.

What steps can reproduce the bug?

import { Hono } from 'hono'

const app = new Hono()
app.get('/*', (c) => c.text('matched'))

console.log((await app.request('/a%20b')).status) // 200
console.log((await app.request('/a%0Ab')).status) // 404  <- expected 200

getPath() runs the path through decodeURI before routing, so %0A becomes a real newline. RegExpRouter compiles a wildcard to ONLY_WILDCARD_REG_EXP_STR = '.*' (and TAIL_WILDCARD_REG_EXP_STR = '(?:|/.*)'), and in JavaScript . never matches a line terminator unless the s flag is set. The route therefore cannot match and the request falls through to the not-found handler.

Named parameters are not affected, because LABEL_REG_EXP_STR = '[^/]+' does match those characters:

app.get('/:p', (c) => c.text('matched')) // '/a%0Ab' -> 200

I ran into this with a route that accepts free text in a path segment: any text containing a newline 404s, while everything else works.

What is the expected behavior?

A wildcard route matches any path, including one whose decoded form contains a line terminator, the same way a named parameter already does.

What do you see instead?

A 404 from the not-found handler. The route handler is never called.

The affected characters are exactly the four JavaScript line terminators: \n (%0A), \r (%0D), \u2028 (%E2%80%A8) and \u2029 (%E2%80%A9). Tab, form feed, vertical tab and NUL all match fine.

With app.get('/*', ...) and a request to /a%0Ab:

Router Result
SmartRouter (default) 404
RegExpRouter 404
TrieRouter 200
PatternRouter 200
LinearRouter 200

SmartRouter cannot route around this. It selects a router on the first request and only moves on when add() throws UnsupportedPathError; RegExpRouter registers the route without complaint and merely fails to match later, which is indistinguishable from a genuine 404.

Only the wildcard patterns are affected. A wildcard in the middle of a path, such as /files/*/download, compiles to LABEL_REG_EXP_STR and matches correctly.

Additional information

new Hono({ router: new TrieRouter() }) is a working workaround.

A fix might be to make the wildcard patterns match line terminators, for example '[\s\S]*' in place of '.*' and '(?:|/[\s\S]*)' in place of '(?:|/.*)', or to compile the matcher with the s flag.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions