mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 17:04:58 +00:00
fix(security): block private/loopback/metadata IPs in link-understanding URL detection (#15604)
* fix(security): block private/loopback/metadata IPs in link-understanding URL detection isAllowedUrl() only blocked 127.0.0.1, leaving localhost, ::1, 0.0.0.0, private RFC1918 ranges, link-local (169.254.x.x including cloud metadata), and CGNAT (100.64.0.0/10) accessible for SSRF via link-understanding. Add comprehensive hostname/IP blocking consistent with the SSRF guard already used by media/fetch.ts. * fix(security): harden link-understanding SSRF host checks * fix: note link-understanding SSRF hardening in changelog (#15604) (thanks @AI-Reviewer-QS) --------- Co-authored-by: Yi LIU <yi@quantstamp.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -23,4 +23,44 @@ describe("extractLinksFromMessage", () => {
|
||||
const links = extractLinksFromMessage("http://127.0.0.1/test https://ok.test");
|
||||
expect(links).toEqual(["https://ok.test"]);
|
||||
});
|
||||
|
||||
it("blocks localhost and common loopback addresses", () => {
|
||||
expect(extractLinksFromMessage("http://localhost/secret")).toEqual([]);
|
||||
expect(extractLinksFromMessage("http://foo.localhost/secret")).toEqual([]);
|
||||
expect(extractLinksFromMessage("http://service.local/secret")).toEqual([]);
|
||||
expect(extractLinksFromMessage("http://service.internal/secret")).toEqual([]);
|
||||
expect(extractLinksFromMessage("http://0.0.0.0/secret")).toEqual([]);
|
||||
expect(extractLinksFromMessage("http://[::1]/secret")).toEqual([]);
|
||||
});
|
||||
|
||||
it("blocks private network ranges", () => {
|
||||
expect(extractLinksFromMessage("http://10.0.0.1/internal")).toEqual([]);
|
||||
expect(extractLinksFromMessage("http://172.16.0.1/internal")).toEqual([]);
|
||||
expect(extractLinksFromMessage("http://192.168.1.1/internal")).toEqual([]);
|
||||
});
|
||||
|
||||
it("blocks link-local and cloud metadata addresses", () => {
|
||||
expect(extractLinksFromMessage("http://169.254.169.254/latest/meta-data/")).toEqual([]);
|
||||
expect(extractLinksFromMessage("http://169.254.1.1/test")).toEqual([]);
|
||||
expect(extractLinksFromMessage("http://metadata.google.internal/computeMetadata/v1/")).toEqual(
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
it("blocks CGNAT range used by Tailscale", () => {
|
||||
expect(extractLinksFromMessage("http://100.100.50.1/test")).toEqual([]);
|
||||
});
|
||||
|
||||
it("blocks private and mapped IPv6 addresses", () => {
|
||||
expect(extractLinksFromMessage("http://[::ffff:127.0.0.1]/secret")).toEqual([]);
|
||||
expect(extractLinksFromMessage("http://[fe80::1]/secret")).toEqual([]);
|
||||
expect(extractLinksFromMessage("http://[fc00::1]/secret")).toEqual([]);
|
||||
});
|
||||
|
||||
it("allows legitimate public URLs", () => {
|
||||
expect(extractLinksFromMessage("https://example.com/page")).toEqual([
|
||||
"https://example.com/page",
|
||||
]);
|
||||
expect(extractLinksFromMessage("https://8.8.8.8/dns")).toEqual(["https://8.8.8.8/dns"]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user