restify / restify/node-restify

A single malformed Host header crashes the process

Open
#2,011 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
10.7k
Forks
975
Avg merge
1d 6h
Merged PRs (30d)
5

Description

  • Used appropriate template for the issue type
  • Searched both open and closed issues for duplicates of this issue
  • Title adequately and concisely reflects the feature or the bug

Restify Version: 12.0.0
Node.js Version: 24.13.0

Expected behaviour

A request with a malformed Host header should not crash the server.

Actual behaviour

The process exits on a request with a malformed Host header.

TypeError: Invalid URL
    at new URL (node:internal/url:828:25)
    at IncomingMessage.getUrl (node_modules/restify/lib/request.js:472:23)
    at Router.lookup (node_modules/restify/lib/router.js:81:24)
    at Server._runRoute (node_modules/restify/lib/server.js:1115:36)
    at Server._afterPre (node_modules/restify/lib/server.js:1097:10)
  code: 'ERR_INVALID_URL',
  input: 'http://foo|bar/x'

restify 11.1.0 is not affected.

Repro case

// server.js — npm i restify@12.0.0 && node server.js
const restify = require('restify');

const server = restify.createServer();

server.get('/x', function(req, res, next) {
    res.send({ ok: 1 });
    return next();
});

server.listen(8401, '127.0.0.1');

This request kills it:

# malformed Host header
curl -H 'Host: foo|bar' http://127.0.0.1:8401/x

Cause

Request.prototype.getUrl
builds a WHATWG URL from two client-supplied inputs — the Host header as the authority,
and the request target:

var base = protocol + (this.headers.host || 'localhost');
this._url = this.url.charAt(0) === '/'
    ? new URL(base + this.url)
    : new URL(this.url, base);

Node's HTTP parser validates neither as a URL, so either can make new URL() throw.

Router.lookup
calls req.getUrl().pathname on every request, reached from
Server._runRoute.
Nothing on that path catches, and createServer defaults handleUncaughtExceptions to
false, so the exception is uncaught and the process exits.

Introduced in 12.0.0 by #1996. Before that, getUrl() was url.parse(this.url), which is
path-only and never reads the Host header.

Are you willing and able to fix this?

Yes — I have a patch and two regression tests ready, and will open a PR.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with lib/request.js at Request.prototype.getUrl, then trace the calls through lib/router.js and lib/server.js. Run the provided server.js and curl reproduction first; done means malformed Host or request-target input no longer exits the process and the two regression tests pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.