siyuan-note/siyuan · warning
ip address [ ] is prohibited
Error message
ip address [%s] is prohibited
What it means
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.
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)
Example fix
// before (SafeMode on, target on LAN)
resp, err := client.R().Get("http://192.168.1.10:8080/api") // ip address [192.168.1.10] is prohibited
// after: move service behind a public resolvable endpoint or disable safe mode for the trusted deployment
util.SafeMode = false
resp, err := client.R().Get("http://192.168.1.10:8080/api") Defensive patterns
Strategy: validation
Validate before calling
// Go: pre-check whether the target IP would be blocked under SafeMode
host, _, _ := net.SplitHostPort(addr)
if ip := net.ParseIP(host); ip != nil && util.SafeMode {
// refuse early or route to a public endpoint before dialing
}
Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- access to private/internal IP is prohibited
- access to private/internal IP is prohibited
- failed to resolve host:
- generated image URL resolved to a private or invalid IP
- host has no public IP:
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/448491c89fc442d6.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/util/net.go:184
host = strings.ToLower(strings.TrimSuffix(strings.TrimSuffix(strings.TrimSpace(host), ":80"), ":443"))
return "" != originHost && originHost == host
}
// SSRFSafeDialer returns a net.Dialer whose Control hook blocks private, loopback, link-local and unspecified IPs.
func SSRFSafeDialer(timeout time.Duration) *net.Dialer {
return &net.Dialer{
Timeout: timeout,
Control: func(network, address string, _ syscall.RawConn) error {
host, _, err := net.SplitHostPort(address)
if err != nil {
return err
}
if ip := net.ParseIP(host); ip != nil && isPrivateIP(ip) {
if _, loaded := auditedAddresses.LoadOrStore(address, struct{}{}); !loaded {
logging.LogWarnf("Establishing a connection to the private network [address=%s, network=%s]", address, network)
}
if SafeMode {
return fmt.Errorf("ip address [%s] is prohibited", host)
}
}
return nil
},
}
}
// ssrfSafeDialContext 返回智能体出站请求专用的拨号函数:拨号时自行解析主机名并拒绝私网地址,
// 同时直接连接解析出的公网 IP,使 CheckHostSSRF 的守卫结果与拨号目标一致,
// 从根上杜绝 DNS 重绑定导致的 TOCTOU 绕过。
// 与 SSRFSafeDialer 不同,本拨号函数不依赖 SafeMode,始终强制执行。
// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-x8gv-g2g3-65fj
func ssrfSafeDialContext(timeout time.Duration) func(ctx context.Context, network, addr string) (net.Conn, error) {
dialer := &net.Dialer{Timeout: timeout}
return func(ctx context.Context, network, addr string) (net.Conn, error) {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil, errView on GitHub (pinned to 9f775e8a12)