From 09d4f3ffb22966683f3c8ac50cfd3f453c62eece Mon Sep 17 00:00:00 2001 From: Chengpeng Wang <160559616+chengpeng-wang@users.noreply.github.com> Date: Tue, 3 Mar 2026 12:51:24 +0800 Subject: [PATCH] Resolve SSRF in the function Execute Add a function to block requests to private/internal addresses. SSRF resolved. --- pkg/tools/web.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pkg/tools/web.go b/pkg/tools/web.go index 10498126b..37bdfdb25 100644 --- a/pkg/tools/web.go +++ b/pkg/tools/web.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + "net" "net/http" "net/url" "regexp" @@ -582,6 +583,24 @@ func (t *WebFetchTool) Parameters() map[string]any { } } +func blockPrivateTarget(ctx context.Context, parsedURL *url.URL) error { + hostname := parsedURL.Hostname() // strips port and IPv6 brackets + addrs, err := net.DefaultResolver.LookupHost(ctx, hostname) + if err != nil { + return fmt.Errorf("could not resolve host %q", hostname) + } + for _, addr := range addrs { + ip := net.ParseIP(addr) + if ip == nil { + continue + } + if ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsUnspecified() { + return fmt.Errorf("requests to private/internal addresses are not allowed") + } + } + return nil +} + func (t *WebFetchTool) Execute(ctx context.Context, args map[string]any) *ToolResult { urlStr, ok := args["url"].(string) if !ok { @@ -601,6 +620,10 @@ func (t *WebFetchTool) Execute(ctx context.Context, args map[string]any) *ToolRe return ErrorResult("missing domain in URL") } + if err := blockPrivateTarget(ctx, parsedURL); err != nil { + return ErrorResult(err.Error()) + } + maxChars := t.maxChars if mc, ok := args["maxChars"].(float64); ok { if int(mc) > 100 {