From 8be3c2038eebf4ae12481683a1e809b314be3151 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Sat, 18 Jan 2025 14:13:27 +0900 Subject: [PATCH] `lookupWebFinger()`: avoid SSRF attacks https://github.com/dahlia/fedify/security/advisories/GHSA-c59p-wq67-24wx --- CHANGES.md | 5 +++++ src/webfinger/lookup.test.ts | 19 ++++++++++++++++++- src/webfinger/lookup.ts | 2 ++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 434c7fc2..d52cf556 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -19,6 +19,11 @@ To be released. could lead to a security breach. Now it follows only the same scheme as the original request. + - Fixed a security vulnerability where the `lookupWebFinger()` function + had followed the redirects to the private network addresses, which + could lead to a SSRF attack. Now it follows only the public network + addresses. + Version 1.0.13 -------------- diff --git a/src/webfinger/lookup.test.ts b/src/webfinger/lookup.test.ts index e76ea7fb..b7af79ec 100644 --- a/src/webfinger/lookup.test.ts +++ b/src/webfinger/lookup.test.ts @@ -1,6 +1,7 @@ -import { assertEquals } from "@std/assert"; +import { assertEquals, assertRejects } from "@std/assert"; import { deadline } from "@std/async/deadline"; import * as mf from "mock_fetch"; +import { UrlError } from "../runtime/url.ts"; import { test } from "../testing/mod.ts"; import type { ResourceDescriptor } from "./jrd.ts"; import { lookupWebFinger } from "./lookup.ts"; @@ -122,6 +123,22 @@ test("lookupWebFinger()", async (t) => { assertEquals(await lookupWebFinger("acct:johndoe@example.com"), null); }); + mf.mock( + "GET@/.well-known/webfinger", + (_) => + new Response("", { + status: 302, + headers: { Location: "https://localhost/" }, + }), + ); + + await t.step("redirection to private address", async () => { + await assertRejects( + () => lookupWebFinger("acct:johndoe@example.com"), + UrlError, + ); + }); + mf.uninstall(); }); diff --git a/src/webfinger/lookup.ts b/src/webfinger/lookup.ts index 45952a3a..5364cb27 100644 --- a/src/webfinger/lookup.ts +++ b/src/webfinger/lookup.ts @@ -1,4 +1,5 @@ import { getLogger } from "@logtape/logtape"; +import { validatePublicUrl } from "../runtime/url.ts"; import type { ResourceDescriptor } from "./jrd.ts"; const logger = getLogger(["fedify", "webfinger", "lookup"]); @@ -35,6 +36,7 @@ export async function lookupWebFinger( { url: url.href }, ); let response: Response; + await validatePublicUrl(url.href); try { response = await fetch(url, { headers: { Accept: "application/jrd+json" },