projectdiscovery/nuclei · error

both follow host redirects and follow redirects specified

Error message

both follow host redirects and follow redirects specified

What it means

Variant of the source-IP check when only -source-ip is provided: nuclei verifies the address against every interface ('any'); if none owns it, startup aborts. Typical when the address is stale, belongs to another machine, or is a public/NAT address rather than one assigned locally.

Source

Thrown at internal/runner/options.go:164

		if _, ok := err.(*validator.InvalidValidationError); ok {
			return err
		}
		errs := []string{}
		for _, err := range err.(validator.ValidationErrors) {
			errs = append(errs, err.Namespace()+": "+err.Tag())
		}
		return errors.Wrap(errors.New(strings.Join(errs, ", ")), "validation failed for these fields")
	}
	if options.Verbose && options.Silent {
		return errors.New("both verbose and silent mode specified")
	}

	if (options.HeadlessOptionalArguments != nil || options.ShowBrowser || options.UseInstalledChrome) && !options.Headless {
		return errors.New("headless mode (-headless) is required if -ho, -sb, -sc or -lha are set")
	}

	if options.FollowHostRedirects && options.FollowRedirects {
		return errors.New("both follow host redirects and follow redirects specified")
	}
	if options.ShouldFollowHTTPRedirects() && options.DisableRedirects {
		return errors.New("both follow redirects and disable redirects specified")
	}
	// loading the proxy server list from file or cli and test the connectivity
	if err := loadProxyServers(options); err != nil {
		return err
	}
	if options.Validate {
		validateTemplatePaths(options.Logger, config.DefaultConfig.TemplatesDirectory, options.Templates, options.Workflows)
	}
	if options.DAST {
		if err := validateDASTOptions(options); err != nil {
			return err
		}
	}

	// Verify if any of the client certificate options were set since it requires all three to work properly

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. List local addresses with ip addr (or ifconfig) and pass one of them
  2. On multi-homed hosts pick the address of the egress interface
  3. Remove -source-ip to let the OS choose the source address

Example fix

# before
nuclei -source-ip 203.0.113.7 -t tpl.yaml
# after
nuclei -source-ip 192.168.1.20 -t tpl.yaml
Defensive patterns

Strategy: validation

Validate before calling

import "net"

func ipAnywhere(ip string) bool {
    addrs, err := net.InterfaceAddrs()
    if err != nil {
        return false
    }
    for _, a := range addrs {
        if ipnet, ok := a.(*net.IPNet); ok && ipnet.IP.String() == ip {
            return true
        }
    }
    return false
}

Prevention

When it happens

Trigger: nuclei -source-ip 203.0.113.7 on a host whose interfaces only hold 192.168.x.x; an address from a previous DHCP lease; a typo in the flag.

Common situations: Laptops roaming between networks; scripts hard-coding an old IP; users passing the target's public IP instead of a local source address.

Related errors


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/e909864ec55784ce. Report an issue: GitHub.