Skip to content

Http server message.url does not follow the whatwg url standard and does not evaluate ../Β #51311

@stefanbeigel

Description

@stefanbeigel

Version

18.17.1

Platform

All

Subsystem

No response

What steps will reproduce the bug?

I would like to share with you a very common scenario:

  1. A request is recevied via NodeJs Express or Fastify server using http module.
  2. Request is forwarded to another service using an http client that uses the whatwg URL class to build the target URL using the service hostname + the incoming message url

Express and fastify route matching is done on the incoming message url, which is not whatwg compliant url, see also discussion here This scenario can lead to path traversal vulnerabilities as the whatwg URL class will evaluate ../ and ./ but the server has matched on another path.

This situation is not good at all, because the developer need to know about the different parsing logic. I created this issue at Nodejs as the root cause of this the url property of the incoming message. As you can see in the linked property the fastify maintainer says that

Fastify never aimed to be compatible with the WHATWG Url parsing standard.

Having different url representations in one framework/language is not good at all.

Example application

I have prepared a sample application using fastify:
https://github.com/stefanbeigel/whatwg-fastify-path-traversal/blob/main/index.mjs
Call the app with curl --path-as-is localhost:3000/abc/../foobar

How often does it reproduce? Is there a required condition?

What is the expected behavior? Why is that the expected behavior?

  1. Parse the incoming message url with WHATWG url class

OR

  1. Drop the whatwg standard for the URL class, as it mainly used for browsers.

What do you see instead?

Additional information

Fastify: Different URL parsing between fastify and URL whatwg standard
WhatWG: URL path shortening for ../ creates problem with other URL parsers that do not follow the whatwg standard
Discussion: http(s) server why is request.url actually not an url, but a pathname. And why is parsing it now so hard?

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