{"record":{"id":"448491c89fc442d6","repo":"siyuan-note/siyuan","slug":"ip-address-s-is-prohibited","errorCode":null,"errorMessage":"ip address [%s] is prohibited","messagePattern":"ip address \\[(.+?)\\] is prohibited","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/util/net.go","lineNumber":184,"sourceCode":"\thost = strings.ToLower(strings.TrimSuffix(strings.TrimSuffix(strings.TrimSpace(host), \":80\"), \":443\"))\n\treturn \"\" != originHost && originHost == host\n}\n\n// SSRFSafeDialer returns a net.Dialer whose Control hook blocks private, loopback, link-local and unspecified IPs.\nfunc SSRFSafeDialer(timeout time.Duration) *net.Dialer {\n\treturn &net.Dialer{\n\t\tTimeout: timeout,\n\t\tControl: func(network, address string, _ syscall.RawConn) error {\n\t\t\thost, _, err := net.SplitHostPort(address)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif ip := net.ParseIP(host); ip != nil && isPrivateIP(ip) {\n\t\t\t\tif _, loaded := auditedAddresses.LoadOrStore(address, struct{}{}); !loaded {\n\t\t\t\t\tlogging.LogWarnf(\"Establishing a connection to the private network [address=%s, network=%s]\", address, network)\n\t\t\t\t}\n\t\t\t\tif SafeMode {\n\t\t\t\t\treturn fmt.Errorf(\"ip address [%s] is prohibited\", host)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n}\n\n// ssrfSafeDialContext 返回智能体出站请求专用的拨号函数：拨号时自行解析主机名并拒绝私网地址，\n// 同时直接连接解析出的公网 IP，使 CheckHostSSRF 的守卫结果与拨号目标一致，\n// 从根上杜绝 DNS 重绑定导致的 TOCTOU 绕过。\n// 与 SSRFSafeDialer 不同，本拨号函数不依赖 SafeMode，始终强制执行。\n// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-x8gv-g2g3-65fj\nfunc ssrfSafeDialContext(timeout time.Duration) func(ctx context.Context, network, addr string) (net.Conn, error) {\n\tdialer := &net.Dialer{Timeout: timeout}\n\treturn func(ctx context.Context, network, addr string) (net.Conn, error) {\n\t\thost, port, err := net.SplitHostPort(addr)\n\t\tif err != nil {\n\t\t\treturn nil, err","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/util/net.go#L166-L202","documentation":"SSRFSafeDialer installs a Control hook on a net.Dialer that inspects every dialed address. When the target IP is private/loopback/link-local (per isPrivateIP) and the SafeMode flag is on, the dial is blocked with \"ip address [%s] is prohibited\" to prevent SSRF attacks against internal networks. This is an intentional security guard, not a bug.","triggerScenarios":"Any outbound HTTP/request made through the SSRFSafeDialer while conf SafeMode is enabled and the resolved target IP is private (10.x, 172.16-31.x, 192.168.x, 127.x, link-local, or IPv6 transition addresses embedding private IPv4).","commonSituations":"SafeMode enabled (e.g. when accessed over untrusted networks) while SiYuan tries to reach a self-hosted service on the LAN — a webhook, local LLM server, internal mirror, or a hostname that resolves to the machine's own LAN IP.","solutions":["If the private target is legitimate, disable SafeMode (safe mode setting in SiYuan) or connect from a trusted network context","Use a public hostname/IP for the service instead of a private LAN address","Whitelist per policy: if you control the code, bypass SSRFSafeDialer for explicitly trusted internal endpoints (with care)","Check that DNS is not unexpectedly resolving the target to a private IP (split-horizon DNS, hosts-file entries)"],"exampleFix":"// before (SafeMode on, target on LAN)\nresp, err := client.R().Get(\"http://192.168.1.10:8080/api\") // ip address [192.168.1.10] is prohibited\n// after: move service behind a public resolvable endpoint or disable safe mode for the trusted deployment\nutil.SafeMode = false\nresp, err := client.R().Get(\"http://192.168.1.10:8080/api\")","handlingStrategy":"validation","validationCode":"// Go: pre-check whether the target IP would be blocked under SafeMode\nhost, _, _ := net.SplitHostPort(addr)\nif ip := net.ParseIP(host); ip != nil && util.SafeMode {\n    // refuse early or route to a public endpoint before dialing\n}\n","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Document that SafeMode blocks LAN targets so operators don't point integrations at internal IPs while it is on","Prefer public, DNS-resolvable endpoints for external integrations","Check the SafeMode flag in deployment configuration before wiring internal service URLs","Watch for split-horizon DNS that makes a public name resolve privately"],"tags":["go","network","ssrf","security"],"backgroundTag":"private-ip-blocked","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}