Skip to content

Commit 0d8f9aa

Browse files
committed
Merge tag '0.9.3' into 0.10-maintenance
Fedify 0.9.3
2 parents dd43d0c + 7600281 commit 0d8f9aa

File tree

2 files changed

+35
-7
lines changed

2 files changed

+35
-7
lines changed

CHANGES.md

+24
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ Version 0.10.2
88

99
To be released.
1010

11+
- Fixed a vulnerability of SSRF via DNS rebinding in the built-in document
12+
loader. [[CVE-2024-39687]]
13+
14+
- The `fetchDocumentLoader()` function now throws an error when the given
15+
domain name has any records referring to a private network address.
16+
- The `getAuthenticatedDocumentLoader()` function now returns a document
17+
loader that throws an error when the given domain name has any records
18+
referring to a private network address.
19+
1120

1221
Version 0.10.1
1322
--------------
@@ -185,6 +194,21 @@ is now distributed under the [MIT License] to encourage wider adoption.
185194
[x-forwarded-fetch]: https://github.com/dahlia/x-forwarded-fetch
186195

187196

197+
Version 0.9.3
198+
-------------
199+
200+
Released on July 9, 2024.
201+
202+
- Fixed a vulnerability of SSRF via DNS rebinding in the built-in document
203+
loader. [[CVE-2024-39687]]
204+
205+
- The `fetchDocumentLoader()` function now throws an error when the given
206+
domain name has any records referring to a private network address.
207+
- The `getAuthenticatedDocumentLoader()` function now returns a document
208+
loader that throws an error when the given domain name has any records
209+
referring to a private network address.
210+
211+
188212
Version 0.9.2
189213
-------------
190214

runtime/url.ts

+11-7
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,17 @@ export async function validatePublicUrl(url: string): Promise<void> {
3030
const netPermission = await Deno.permissions.query({ name: "net" });
3131
if (netPermission.state !== "granted") return;
3232
}
33-
const { address, family } = await lookup(hostname);
34-
if (
35-
family === 4 && !isValidPublicIPv4Address(address) ||
36-
family === 6 && !isValidPublicIPv6Address(address) ||
37-
family < 4 || family === 5 || family > 6
38-
) {
39-
throw new UrlError(`Invalid or private address: ${address}`);
33+
// To prevent SSRF via DNS rebinding, we need to resolve all IP addresses
34+
// and ensure that they are all public:
35+
const addresses = await lookup(hostname, { all: true });
36+
for (const { address, family } of addresses) {
37+
if (
38+
family === 4 && !isValidPublicIPv4Address(address) ||
39+
family === 6 && !isValidPublicIPv6Address(address) ||
40+
family < 4 || family === 5 || family > 6
41+
) {
42+
throw new UrlError(`Invalid or private address: ${address}`);
43+
}
4044
}
4145
}
4246

0 commit comments

Comments
 (0)