{"record":{"id":"80138dc6243591f0","repo":"siyuan-note/siyuan","slug":"access-to-private-internal-ip-is-prohibited","errorCode":null,"errorMessage":"access to private/internal IP is prohibited","messagePattern":"access to private/internal IP is prohibited","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/httprequest.go","lineNumber":50,"sourceCode":"\nconst (\n\tmaxHTTPRequestBytes     = 5 * 1024 * 1024  // text/html、text/plain、application/json 等文本类响应上限\n\tmaxHTTPRequestFileBytes = 10 * 1024 * 1024 // 二进制响应落盘上限\n\tmaxHTTPRequestChars     = 50000\n)\n\n// CheckHostSSRF 校验主机名解析出的 IP 不落在内网/回环等不可达地址段，\n// 防止智能体被诱导发起 SSRF 攻击。web_fetch 与 http_request 共用此校验。\n// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-rg26-cg95-gq6p\nfunc CheckHostSSRF(host string) error {\n\tips, err := net.LookupIP(host)\n\tif err != nil {\n\t\treturn errors.New(\"failed to resolve host: \" + err.Error())\n\t}\n\tfor _, ip := range ips {\n\t\t// 与 SSRFSafeDialer 共用 isPrivateIP，覆盖 NAT64、6to4、Teredo 等 IPv6 过渡地址。\n\t\tif isPrivateIP(ip) {\n\t\t\treturn errors.New(\"access to private/internal IP is prohibited\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// HTTPRequest 发起一次通用 HTTP 调用，供智能体 http_request 工具使用。\n// 与 WebFetch 不同：本函数不做 HTML→Markdown 转换，文本类响应（含 JSON/XML）原样返回，\n// 便于智能体直接消费 REST API 的 JSON 输出。method 取值：GET/POST/PUT/DELETE/PATCH。\n// 返回的 text 为响应正文（文本类）或落盘后的文件路径（二进制类）。\nfunc HTTPRequest(method, rawURL string, headers map[string]string, body string) (statusCode int, contentType string, text string, err error) {\n\tu, err := url.Parse(rawURL)\n\tif err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") {\n\t\treturn 0, \"\", \"\", errors.New(\"URL must start with http:// or https://\")\n\t}\n\tif u.Host == \"\" {\n\t\treturn 0, \"\", \"\", errors.New(\"URL has no host\")\n\t}\n","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/util/httprequest.go#L32-L68","documentation":"Returned by CheckHostSSRF when any IP returned by net.LookupIP is classified as private by isPrivateIP (net.go:175). isPrivateIP covers loopback, link-local, multicast, unspecified, RFC1918/IsPrivate ranges, and embedded-IPv4 IPv6 transition addresses (NAT64, 6to4, Teredo). This is the core SSRF defense (GHSA-rg26-cg95-gq6p) and is by design non-bypassable for the http_request / web_fetch tools.","triggerScenarios":"HTTPRequest or web_fetch targets a host that resolves (or also resolves) to 127.0.0.0/8, 10/8, 172.16/12, 192.168/16, 169.254/16, ::1, fc00::/7, or an IPv6 transition address embedding one of those.","commonSituations":"An agent (or user) pointing the tool at localhost or an internal service to probe the kernel host; a public hostname with a split-horizon DNS that returns an internal IP inside the deployment; link-local 169.254.x.x (cloud metadata, e.g. AWS 169.254.169.254); a NAT64/6to4 hostname used to disguise a private v4 address.","solutions":["Target a genuinely public host whose DNS returns public IPs.","If the internal service must be reached, do not route it through the SSRF-guarded tools — call it directly from trusted kernel code, not via the agent HTTP tool.","Re-check the hostname is not resolving to a private IP via split-horizon DNS (dig from the kernel host)."],"exampleFix":"// before\nutil.HTTPRequest(\"GET\", \"http://localhost:8080/health\", nil, \"\")\n\n// after\n// localhost is private and always rejected by design —\n// call the internal endpoint through a trusted kernel helper instead of the agent HTTP tool.\nmodel.ProbeInternalHealth()","handlingStrategy":"validation","validationCode":"func hostIsPublic(host string) bool {\n    ips, err := net.LookupIP(host)\n    if err != nil { return false }\n    for _, ip := range ips {\n        if ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() || ip.IsUnspecified() {\n            return false\n        }\n    }\n    return true\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not try to bypass SSRF — call internal services from trusted kernel code instead of the agent HTTP tool.","Beware split-horizon DNS: a 'public' hostname may resolve internally inside the deployment."],"tags":["network","ssrf","security","http-request"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}