siyuan-note/siyuan · error
access to private/internal IP is prohibited
Error message
access to private/internal IP is prohibited
What it means
CheckHostSSRF resolves the host and rejects the request if any resolved IP falls into private/loopback/link-local (or IPv6 transition) ranges, via the shared isPrivateIP helper. This blocks SSRF attacks where an agent is tricked into fetching internal resources (see GHSA-rg26-cg95-gq6p).
Solutions
- Test local servers through the browser/editor instead of the agent HTTP fetch tools
- Use the public URL of the resource; internal addresses are intentionally prohibited
- Expose a staging instance on a public host if automated fetching is required
- Never disable or bypass CheckHostSSRF — it addresses a published security advisory
Example fix
// before url: "http://169.254.169.254/latest/meta-data/" // after url: "https://api.example.com/public-resource"
Defensive patterns
Strategy: validation
Validate before calling
ips, err := net.LookupIP(host)
if err == nil {
for _, ip := range ips {
if ip.IsPrivate() || ip.IsLoopback() || ip.IsLinkLocalUnicast() {
return fmt.Errorf("host %s resolves to a private IP; blocked", host)
}
}
} Try / catch
if strings.Contains(err.Error(), "private/internal IP") {
// treat as intentional block; do not bypass, do not retry
} Prevention
- Never point agent fetch tools at localhost or RFC1918 addresses
- DNS rebinding to private IPs is also blocked — trust the check
- Use public endpoints for anything the agent must fetch
- Do not disable CheckHostSSRF — it fixes a published advisory
When it happens
Trigger: HTTPRequest, WebFetch, downloadGeneratedImage, or downloadSkillSource is called with a URL whose host resolves to 127.0.0.1, 10.x/172.16.x/192.168.x, 169.254.x, ::1, fc00::/7, fe80::/10, or NAT64/6to4/Teredo-mapped private addresses.
Common situations: AI agent prompt-injection attempting to read localhost admin endpoints or cloud metadata (169.254.169.254); developers testing against a local server through the agent fetch tools; DNS rebinding to a private address.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- 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:
- ip address [ ] is prohibited
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/80138dc6243591f0.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/util/httprequest.go:57
const (
maxHTTPRequestBytes = 5 * 1024 * 1024 // text/html、text/plain、application/json 等文本类响应上限
maxHTTPRequestFileBytes = 10 * 1024 * 1024 // 二进制响应落盘上限
maxHTTPRequestChars = 50000
)
// CheckHostSSRF 校验主机名解析出的 IP 不落在内网/回环等不可达地址段,
// 防止智能体被诱导发起 SSRF 攻击。web_fetch 与 http_request 共用此校验。
// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-rg26-cg95-gq6p
func CheckHostSSRF(host string) error {
ips, err := net.LookupIP(host)
if err != nil {
return errors.New("failed to resolve host: " + err.Error())
}
for _, ip := range ips {
// 与 SSRFSafeDialer 共用 isPrivateIP,覆盖 NAT64、6to4、Teredo 等 IPv6 过渡地址。
if isPrivateIP(ip) {
return errors.New("access to private/internal IP is prohibited")
}
}
return nil
}
// ssrfSafeClient 是智能体出站请求专用的 HTTP 客户端:直连时将目标固定到已校验的公网 IP,
// 使用代理时则先与用户配置的代理建立隧道,再通过隧道连接固定后的目标 IP,同时保留原始 Host 和 TLS SNI。
// 两种方式都不会在校验后再次按目标域名解析,避免 DNS 重绑定 TOCTOU 绕过。
// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-x8gv-g2g3-65fj
var ssrfSafeClient = newSSRFSafeClient()
func newSSRFSafeClient() *http.Client {
return newSSRFSafeClientWithResolver(net.DefaultResolver.LookupIPAddr)
}
type lookupIPAddrFunc func(context.Context, string) ([]net.IPAddr, error)
type ssrfSafeTransport struct {View on GitHub (pinned to 9f775e8a12)