Open redirect via `//<host>/..%2f<dir>` in directory trailing-slash redirect

オープン 初心者向け
#982 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
78/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
javascript, node.js
領域
backend, cli, security

調査の方向性

lib/core/index.js の decodePathname(parsed.pathname) と、Location ヘッダーを構築するディレクトリの末尾スラッシュリダイレクトから始めてください。提示されたリクエスト形式を使って回帰テストを追加し、リダイレクトがサーバーのオリジン上に留まり、先頭のスラッシュが1つだけであることを確認してください。issue にはテストファイルが記載されていないため、まず既存のリダイレクトテストを探し、該当するテストスイートを実行してください。

索引モデルが issue の本文から書いたものです。

説明

In http-server 14.1.1 and master (0d3b7bb, Node.js v26.13.0), requesting a path starting with //<host>/..%2f<subdir> when the served root contains <subdir> returns a 302 redirect with a scheme-relative Location header (//<host>/..%2f<subdir>/) that browsers resolve to http://<host>/..%2f<subdir>/ (CWE-601; incomplete fix for ecstatic advisory GHSA-9q64-mpxx-87fg).

const httpServer = require('http-server');
const fs = require('fs');

fs.mkdirSync('./test-root/dir', { recursive: true });
const server = httpServer.createServer({ root: './test-root' });

server.listen(0, '127.0.0.1', async () => {
  const { port } = server.server.address();
  const url = `http://127.0.0.1:${port}//evil.example/..%2fdir`;
  const res = await fetch(url, { redirect: 'manual' });
  const loc = res.headers.get('location');
  console.log('Status:', res.status);
  console.log('Location:', loc);
  console.log('Resolved URL:', new URL(loc, url).href);
  server.close();
});

Expected: Location is a single-slash origin-relative path (e.g. Location: /dir/) that stays on http://127.0.0.1:<port>/.

Actual:

Status: 302
Location: //evil.example/..%2fdir/
Resolved URL: http://evil.example/..%2fdir/

Reference: RFC 9110 §10.2.2 (Location header field) and WHATWG URL Standard §4.4 (a relative-URL string beginning with // is parsed as a scheme-relative-special-url whose host is the authority following //); see also GHSA-9q64-mpxx-87fg and commit jfhbrook/node-ecstatic@be6fc25.

In lib/core/index.js, decodePathname(parsed.pathname) decodes %2f and normalizes //evil.example/../dir to pathname = '/dir' (matching the local directory without a trailing slash), but the 302 response constructs Location from the unnormalized parsed.pathname (ensureUriEncoded(${parsed.pathname}/${q})) instead of pathname or a path with leading slashes collapsed ('/' + parsed.pathname.replace(/^[\/\\]+/, '')).

Credit: https://ucsbplse.github.io/

主要言語
JavaScript
スター
14.2k
フォーク
1.6k
PR マージ指標
30日以内にマージされた PR はありません

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

http-party/http-server のほかの issue

http-party/http-server の issue をすべて見る

似ている issue

JavaScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。