fix: block localhost and loopback addresses in SSRF protection (#28622)
* fix: block localhost and loopback addresses in SSRF protection Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: block loopback IPs by hostname in SSRF protection Add 127.0.0.1, ::1, [::1], and 0.0.0.0 to blocked hostnames list for defense-in-depth protection against SSRF attacks targeting localhost. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Romit <romitgabani1.work@gmail.com> Co-authored-by: Romit <85230081+romitg2@users.noreply.github.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
Romit
Romit
parent
fbf6510dd8
commit
ad791f8ea5
@@ -57,12 +57,16 @@ describe("isPrivateIP", () => {
|
||||
|
||||
describe("isBlockedHostname", () => {
|
||||
it.each([
|
||||
"localhost", // loopback hostname
|
||||
"169.254.169.254", // AWS/Azure/DigitalOcean
|
||||
"metadata.google.internal", // GCP
|
||||
"169.254.169.254.", // trailing dot normalization
|
||||
"METADATA.GOOGLE.INTERNAL", // case insensitive
|
||||
])("blocks cloud metadata endpoint %s", (hostname) => {
|
||||
"localhost",
|
||||
"127.0.0.1",
|
||||
"::1",
|
||||
"[::1]",
|
||||
"0.0.0.0",
|
||||
"169.254.169.254",
|
||||
"metadata.google.internal",
|
||||
"169.254.169.254.",
|
||||
"METADATA.GOOGLE.INTERNAL",
|
||||
])("blocks %s", (hostname) => {
|
||||
expect(isBlockedHostname(hostname)).toBe(true);
|
||||
});
|
||||
|
||||
@@ -104,7 +108,8 @@ describe("validateUrlForSSRFSync", () => {
|
||||
["http://example.com/logo.png", "Only HTTPS URLs are allowed"],
|
||||
["ftp://example.com/file", "Only HTTPS URLs are allowed"],
|
||||
["data:text/html,<script>alert(1)</script>", "Non-image data URL"],
|
||||
["https://127.0.0.1/logo.png", "Private IP address"],
|
||||
["https://127.0.0.1/logo.png", "Blocked hostname"],
|
||||
["https://0.0.0.0/logo.png", "Blocked hostname"],
|
||||
["https://169.254.169.254/latest/meta-data/", "Blocked hostname"],
|
||||
["https://localhost/logo.png", "Blocked hostname"],
|
||||
["not-a-url", "Invalid URL format"],
|
||||
@@ -114,7 +119,7 @@ describe("validateUrlForSSRFSync", () => {
|
||||
});
|
||||
|
||||
it.each([
|
||||
["https://[::1]/", "Private IP address"],
|
||||
["https://[::1]/", "Blocked hostname"],
|
||||
["https://[fe80::1]/path", "Private IP address"],
|
||||
["https://[fc00::1]:8080/", "Private IP address"],
|
||||
["https://[::ffff:127.0.0.1]/", "Private IP address"],
|
||||
|
||||
@@ -31,8 +31,10 @@ const CLOUD_METADATA_ENDPOINTS: string[] = [
|
||||
"metadata.google.com", // GCP alternate
|
||||
];
|
||||
|
||||
// Hostnames blocked on Cal.com SaaS (includes metadata + localhost)
|
||||
const BLOCKED_HOSTNAMES: string[] = [...CLOUD_METADATA_ENDPOINTS, "localhost"];
|
||||
const LOOPBACK_HOSTNAMES: string[] = ["localhost", "127.0.0.1", "::1", "[::1]", "0.0.0.0"];
|
||||
|
||||
// Hostnames blocked on Cal.com SaaS (includes metadata + loopback)
|
||||
const BLOCKED_HOSTNAMES: string[] = [...CLOUD_METADATA_ENDPOINTS, ...LOOPBACK_HOSTNAMES];
|
||||
|
||||
const CAL_AVATAR_PATH_REGEX = /^\/api\/avatar\/.+\.png$/;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user