shadow1ng/fscan · error · ErrInvalidURL

%w: invalid port (ErrInvalidURL)

Error message

%w: invalid port (ErrInvalidURL)

What it means

buildTargetURL detects a structurally malformed port when the URL carries no explicit port but its host part embeds one in an unparseable form (via hasMalformedWebURLPort). It returns ErrInvalidURL so callers can distinguish bad input from transport failures.

Source

Thrown at webscan/web_scan.go:120

			protocol = protocolHTTPS
		}
		info.URL = protocol + net.JoinHostPort(info.Host, fmt.Sprint(info.Port))
	} else if !hasProtocolPrefix(info.URL) {
		info.URL = protocolHTTP + normalizeSchemelessWebTarget(info.URL)
	}

	// 解析URL以提取基础部分
	parsedURL, err := url.Parse(info.URL)
	if err != nil {
		return "", fmt.Errorf("%w: %w", ErrInvalidURL, err)
	}
	if parsedURL.Hostname() == "" {
		return "", fmt.Errorf("%w: empty host", ErrInvalidURL)
	}
	portStr := parsedURL.Port()
	if portStr == "" {
		if hasMalformedWebURLPort(parsedURL.Host) {
			return "", fmt.Errorf("%w: invalid port", ErrInvalidURL)
		}
	} else {
		port, err := strconv.Atoi(portStr)
		if err != nil || port < 1 || port > 65535 {
			return "", fmt.Errorf("%w: invalid port %q", ErrInvalidURL, portStr)
		}
	}
	parsedURL.Host = normalizeWebURLHost(parsedURL.Host)

	return fmt.Sprintf("%s://%s", parsedURL.Scheme, parsedURL.Host), nil
}

// hasProtocolPrefix 检查URL是否包含协议前缀
func hasProtocolPrefix(urlStr string) bool {
	urlStr = strings.ToLower(urlStr)
	return strings.HasPrefix(urlStr, protocolHTTP) || strings.HasPrefix(urlStr, protocolHTTPS)
}

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Fix the target URL so the port is either absent or a valid decimal (1-65535), e.g. http://example.com:8080
  2. Check template/placeholder substitution produced a real port value
  3. Validate ports with strconv.Atoi and range check before submitting the target

Example fix

// before
url := fmt.Sprintf("http://%s:%s", host, port) // port may be empty
// after
if port != "" {
    n, err := strconv.Atoi(port)
    if err != nil || n < 1 || n > 65535 {
        return fmt.Errorf("invalid port %q", port)
    }
}
url := fmt.Sprintf("http://%s", net.JoinHostPort(host, port))
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(target)
if err != nil || (u.Port() == "" && strings.Contains(u.Host, ":")) {
    return fmt.Errorf("target %q has malformed port", target)
}

Try / catch

if err := WebScan(target); errors.Is(err, ErrInvalidURL) {
    log.Printf("invalid target URL %q: %v", target, err)
    return nil
}

Prevention

When it happens

Trigger: URLs like "http://example.com:/path" or hosts such as "example.com:port" where url.Parse yields an empty Port() but the raw Host contains a colon segment that is not a valid decimal port.

Common situations: Template string bugs like fmt.Sprintf("http://%s:%s", host, portVar) with empty/placeholder port, copy-paste of URLs with a trailing colon, or port placeholders like :<port> left unsubstituted.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/fdbc9d6470f6cf7f. Report an issue: GitHub.