{"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":"error","filePath":"kernel/util/net.go","lineNumber":164,"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// isPrivateIP 判断 IP 是否为私网地址，含内嵌私网 IPv4 的 IPv6 过渡地址（NAT64、6to4、Teredo、IPv4 兼容）。\n// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-qq8m-8p8v-x4xg\n// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-rg26-cg95-gq6p\nfunc isPrivateIP(ip net.IP) bool {\n\tif ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() ||\n\t\tip.IsPrivate() || ip.IsUnspecified() || ip.IsMulticast() {\n\t\treturn true\n\t}\n\t// Go 标准库的分类方法不识别 IPv6 过渡地址，需按 RFC 内嵌格式提取其中的 IPv4 后再递归判断。\n\tif ip4 := extractEmbeddedIPv4(ip); nil != ip4 && !ip4.Equal(ip) {\n\t\treturn isPrivateIP(ip4)","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/util/net.go#L146-L182","documentation":"SSRFSafeDialer's Control hook resolves the destination and, when SafeMode is on, blocks any private/loopback/link-local/unsup IP (including IPv6 transition addresses that embed private v4) by returning this error. In non-SafeMode the same dialer only logs a warning. It is the SSRF guard for outbound HTTP from AI, sync, bazaar, and plugin features.","triggerScenarios":"Kernel launched in SafeMode makes an outbound request whose hostname resolves to a private address (127.0.0.1, 10/172.16/192.168, .local mDNS, ::1, NAT64/6to4/Teredo embedding private v4).","commonSituations":"AI/embedding endpoint pointed at a localhost service (e.g. local Ollama on 127.0.0.1:11434) while in SafeMode; plugin targeting an internal service; DNS rebinding where a public hostname resolves to a private IP; testing against a local LLM.","solutions":["Restart the kernel WITHOUT SafeMode when you legitimately need to reach a trusted private/loopback endpoint.","Point the endpoint at a genuinely public hostname/IP.","Do not weaken the dialer; SafeMode is opt-in for diagnostics, so a normal launch re-enables private targets (still audited).","Audit plugin/AI endpoints for private addresses before enabling SafeMode."],"exampleFix":"# before: launched in safe mode\nsiyuan --safe   # blocks 127.0.0.1:11434 (local Ollama)\n\n# after: normal launch\nsiyuan          # same private endpoint allowed, still logged","handlingStrategy":"validation","validationCode":"if util.SafeMode {\n    if ip := net.ParseIP(host); ip != nil && isPrivateIP(ip) {\n        return errors.New(\"target blocked in SafeMode; restart normally\")\n    }\n}","typeGuard":"func SafeToDial(host string) bool {\n    if !util.SafeMode { return true }\n    ip := net.ParseIP(host)\n    return ip == nil || !isPrivateIP(ip)\n}","tryCatchPattern":null,"preventionTips":["Exit SafeMode to reach trusted internal endpoints","Use public hostnames for AI/sync targets","Audit plugin endpoints for private addresses before enabling SafeMode"],"tags":["security","ssrf","network","go","safemode"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}