flipped-aurora/gin-vue-admin · warning

目标解析为内网/环回/链路本地地址, 已被 SSRF 防护拒绝(可在任务上开启"允许内网"豁免)

Error message

目标解析为内网/环回/链路本地地址, 已被 SSRF 防护拒绝(可在任务上开启"允许内网"豁免)

What it means

errPrivateAddr is the sentinel returned by the HTTP task executor's SSRF protection when the target URL resolves to a loopback, private (RFC1918), link-local, multicast link-local, or unspecified IP. It prevents server-side request forgery against internal networks; tasks can opt out via an "allow intranet" flag.

Source

Thrown at server/service/system/sys_timed_task_http.go:14

// server/service/system/sys_timed_task_http.go
package system

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"syscall"
	"time"
)

// errPrivateAddr SSRF 防护拒绝(错误信息含"SSRF"关键字, 供日志/测试识别)
var errPrivateAddr = errors.New("目标解析为内网/环回/链路本地地址, 已被 SSRF 防护拒绝(可在任务上开启\"允许内网\"豁免)")

// isDisallowedIP 内网/环回/链路本地/未指定地址判定
func isDisallowedIP(ip net.IP) bool {
	return ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsUnspecified()
}

// ssrfControl 在拨号阶段(DNS 解析后、连接建立前)校验目标 IP:
// 每次连接都过检, 天然覆盖重定向与 DNS rebinding(TOCTOU 安全)。
func ssrfControl(allowPrivate bool) func(network, address string, c syscall.RawConn) error {
	return func(_ string, address string, _ syscall.RawConn) error {
		if allowPrivate {
			return nil
		}
		host, _, err := net.SplitHostPort(address)
		if err != nil {
			return fmt.Errorf("解析拨号地址失败: %w", err)
		}
		ip := net.ParseIP(host)

View on GitHub (pinned to 3136500ef3)

Solutions

  1. If the target is intentionally internal, enable the task's "允许内网" (allow intranet) exemption flag.
  2. Use a publicly reachable https:// endpoint for the task target.
  3. Check DNS resolution of the hostname; if it resolves to a private IP unexpectedly, fix DNS or use the public address.
  4. Avoid loopback/unspecified addresses like localhost or 0.0.0.0 unless exempted.

Example fix

// before
HttpUrl: "http://127.0.0.1:8080/health" // rejected by SSRF guard

// after
task.AllowIntranet = true
HttpUrl: "http://127.0.0.1:8080/health" // allowed with explicit exemption
// or
HttpUrl: "https://api.example.com/health"
Defensive patterns

Strategy: try-catch

Validate before calling

ips, err := net.LookupIP(u.Hostname())
if err == nil {
    for _, ip := range ips {
        if ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() || ip.IsUnspecified() {
            if !task.AllowIntranet {
                return errors.New("target resolves to a private address; enable allow-intranet or use a public endpoint")
            }
        }
    }
}

Try / catch

if err := runner.RunTask(ctx, task); err != nil {
    if strings.Contains(err.Error(), "SSRF") {
        log.Warnf("task %s blocked by SSRF guard; target is internal", task.Name)
        return
    }
    log.Errorf("task %s failed: %v", task.Name, err)
}

Prevention

When it happens

Trigger: Running/creating an HTTP-executor timed task whose URL host is 127.0.0.1, ::1, 10.x, 172.16-31.x, 192.168.x, 169.254.x, 0.0.0.0, or a DNS name resolving to any of these, without the allow-intranet exemption enabled on the task.

Common situations: Pointing tasks at internal microservices (http://localhost:8080/...) in dev configs; docker-compose service names resolving to private IPs; staging tasks moved from public to private endpoints; corporate DNS resolving to internal ranges.

Related errors


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/2d3dc345a6a0ee03. Report an issue: GitHub.