Files
linkwarden/packages/lib/ssrf.test.ts

51 lines
1.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
assertUrlIsSafeForServerSideFetch,
isHostnameBlockedForServerSideFetch,
isIpAddressBlockedForServerSideFetch,
UnsafeUrlError,
} from "./ssrf";
describe("ssrf guard", () => {
it("blocks localhost hostnames", () => {
expect(isHostnameBlockedForServerSideFetch("localhost")).toBe(true);
expect(isHostnameBlockedForServerSideFetch("subdomain.localhost")).toBe(
true
);
});
it("blocks single-label internal hostnames", () => {
expect(isHostnameBlockedForServerSideFetch("meilisearch")).toBe(true);
expect(isHostnameBlockedForServerSideFetch("postgres")).toBe(true);
});
it("blocks private and loopback IP literals", () => {
expect(isIpAddressBlockedForServerSideFetch("127.0.0.1")).toBe(true);
expect(isIpAddressBlockedForServerSideFetch("169.254.169.254")).toBe(true);
expect(isIpAddressBlockedForServerSideFetch("::1")).toBe(true);
expect(isIpAddressBlockedForServerSideFetch("fc00::1")).toBe(true);
});
it("allows public hostnames that resolve to public IPs", async () => {
await expect(
assertUrlIsSafeForServerSideFetch("https://example.com", {
lookup: async () => [{ address: "93.184.216.34", family: 4 }],
})
).resolves.toBeInstanceOf(URL);
});
it("blocks hostnames that resolve to private IPs", async () => {
await expect(
assertUrlIsSafeForServerSideFetch("https://example.com", {
lookup: async () => [{ address: "10.0.0.8", family: 4 }],
})
).rejects.toBeInstanceOf(UnsafeUrlError);
});
it("blocks IPv6 loopback literals", async () => {
await expect(
assertUrlIsSafeForServerSideFetch("http://[::1]/")
).rejects.toBeInstanceOf(UnsafeUrlError);
});
});