{"record":{"id":"5538e3fbfdde61ac","repo":"shadow1ng/fscan","slug":"w-invalid-port-q-errinvalidurl","errorCode":null,"errorMessage":"%w: invalid port %q (ErrInvalidURL)","messagePattern":"%w: invalid port %q \\(ErrInvalidURL\\)","errorType":"validation","errorClass":"ErrInvalidURL","httpStatus":null,"severity":"error","filePath":"webscan/web_scan.go","lineNumber":125,"sourceCode":"\t}\n\n\t// 解析URL以提取基础部分\n\tparsedURL, err := url.Parse(info.URL)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"%w: %w\", ErrInvalidURL, err)\n\t}\n\tif parsedURL.Hostname() == \"\" {\n\t\treturn \"\", fmt.Errorf(\"%w: empty host\", ErrInvalidURL)\n\t}\n\tportStr := parsedURL.Port()\n\tif portStr == \"\" {\n\t\tif hasMalformedWebURLPort(parsedURL.Host) {\n\t\t\treturn \"\", fmt.Errorf(\"%w: invalid port\", ErrInvalidURL)\n\t\t}\n\t} else {\n\t\tport, err := strconv.Atoi(portStr)\n\t\tif err != nil || port < 1 || port > 65535 {\n\t\t\treturn \"\", fmt.Errorf(\"%w: invalid port %q\", ErrInvalidURL, portStr)\n\t\t}\n\t}\n\tparsedURL.Host = normalizeWebURLHost(parsedURL.Host)\n\n\treturn fmt.Sprintf(\"%s://%s\", parsedURL.Scheme, parsedURL.Host), nil\n}\n\n// hasProtocolPrefix 检查URL是否包含协议前缀\nfunc hasProtocolPrefix(urlStr string) bool {\n\turlStr = strings.ToLower(urlStr)\n\treturn strings.HasPrefix(urlStr, protocolHTTP) || strings.HasPrefix(urlStr, protocolHTTPS)\n}\n\nfunc isTLSPort(port int) bool {\n\tswitch port {\n\tcase 443, 8443, 4443, 9443:\n\t\treturn true\n\tdefault:","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/webscan/web_scan.go#L107-L143","documentation":"When the URL has an explicit port string, buildTargetURL parses it with strconv.Atoi and requires 1-65535; otherwise it wraps ErrInvalidURL with the offending port quoted. This is a strict numeric/range validation of the port extracted by url.Parse.","triggerScenarios":"URLs like http://example.com:0, http://example.com:99999, http://example.com:80a, or any non-numeric port segment after the colon (e.g. http://example.com:%PORT).","commonSituations":"Unsubstituted environment/templated variables (:${PORT}), typos in hardcoded ports, or port numbers copied from other protocols exceeding 65535.","solutions":["Use a valid port in 1-65535 (e.g. :8080, :443)","Ensure template variables supplying the port are substituted with numeric values","Validate the port with strconv.Atoi + range check in the config layer before invoking WebScan"],"exampleFix":"// before\nconst url = \"http://example.com:99999\"\n// after\nconst url = \"http://example.com:8443\"","handlingStrategy":"validation","validationCode":"if p := u.Port(); p != \"\" {\n    n, err := strconv.Atoi(p)\n    if err != nil || n < 1 || n > 65535 {\n        return fmt.Errorf(\"target %q has invalid port %q\", target, p)\n    }\n}","typeGuard":"func validPort(s string) bool {\n    n, err := strconv.Atoi(s)\n    return err == nil && n >= 1 && n <= 65535\n}","tryCatchPattern":"if err := WebScan(target); errors.Is(err, ErrInvalidURL) {\n    log.Printf(\"rejecting target %q: %v\", target, err)\n    return nil\n}","preventionTips":["Range-check ports at config load time","Never hardcode ports above 65535","Expand environment variables in URLs before validation"],"tags":["url","port","range-check"],"backgroundTag":"value-out-of-range","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}