{"record":{"id":"794d6953d6ba7f86","repo":"valyala/fasthttp","slug":"invalid-scheme-q","errorCode":null,"errorMessage":"invalid scheme %q","messagePattern":"invalid scheme %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"uri.go","lineNumber":293,"sourceCode":"// host may be nil. In this case uri must contain fully qualified uri,\n// i.e. with scheme and host. http is assumed if scheme is omitted.\n//\n// uri may contain e.g. RequestURI without scheme and host if host is non-empty.\nfunc (u *URI) Parse(host, uri []byte) error {\n\treturn u.parse(host, uri, false)\n}\n\nfunc (u *URI) parse(host, uri []byte, isTLS bool) error {\n\tu.Reset()\n\n\tif stringContainsCTLByte(uri) {\n\t\treturn ErrorInvalidURI\n\t}\n\n\tif len(host) == 0 || bytes.Contains(uri, strColonSlashSlash) {\n\t\tscheme, newHost, newURI := splitHostURI(host, uri)\n\t\tif len(scheme) > 0 && !isValidScheme(scheme) {\n\t\t\treturn fmt.Errorf(\"invalid scheme %q\", scheme)\n\t\t}\n\t\tu.SetSchemeBytes(scheme)\n\t\thost = newHost\n\t\turi = newURI\n\t}\n\n\tif isTLS {\n\t\tu.SetSchemeBytes(strHTTPS)\n\t}\n\n\tif n := bytes.LastIndexByte(host, '@'); n >= 0 {\n\t\tauth := host[:n]\n\t\tif !validUserinfo(auth) {\n\t\t\treturn ErrorInvalidURI\n\t\t}\n\t\thost = host[n+1:]\n\n\t\tif before, after, ok := bytes.Cut(auth, []byte{':'}); ok {","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/uri.go#L275-L311","documentation":"fasthttp's URI.Parse validates the scheme extracted when the URI contains a host part. If splitHostURI yields a non-empty scheme that fails isValidScheme (only alphanumerics, '+', '-', '.' allowed), parse returns \"invalid scheme %q\". Parse is fasthttp's low-level URI parsing entry point used when rebinding URIs from raw bytes.","triggerScenarios":"Calling URI.Parse(nil, dst, uri) with a URI whose scheme contains illegal characters, e.g. \"ht tp://host/\", \"http$://host/\", or a malformed proxy-form request line that mis-splits into a bogus scheme.","commonSituations":"Parsing attacker-supplied or corrupted request targets; reverse-proxy code feeding raw request lines into Parse; hand-built URIs with typos like \"hxxp://\".","solutions":["Sanitize/validate the scheme before calling Parse (regex ^[a-zA-Z][a-zA-Z0-9+.-]*$)","Normalize to lowercase http/https at the producer side","If the input is a request line, use RequestHeader/Request parsing instead of raw URI.Parse","Catch the error and reject the request with 400 Bad Request"],"exampleFix":"// before\nvar u uri.URI\nerr := u.Parse(nil, nil, []byte(\"ht tp://example.com/\")) // invalid scheme\n// after\nraw := []byte(\"ht tp://example.com/\")\nif !isValidSchemeBytes(raw) { // reject or fix before parse\n    return errors.New(\"bad scheme\")\n}\nvar u uri.URI\nerr := u.Parse(nil, nil, raw)","handlingStrategy":"validation","validationCode":"var schemeRe = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9+.-]*$`)\nfunc schemeValid(raw []byte) bool {\n    i := bytes.Index(raw, []byte(\"://\"))\n    return i < 0 || schemeRe.Match(raw[:i])\n}","typeGuard":null,"tryCatchPattern":"var u uri.URI\nif err := u.Parse(nil, nil, raw); err != nil {\n    if strings.HasPrefix(err.Error(), \"invalid scheme\") {\n        return fmt.Errorf(\"rejecting request, %w\", err) // map to 400\n    }\n    return err\n}","preventionTips":["Normalize schemes to lowercase http/https at the producer","Never feed raw untrusted request lines straight into URI.Parse","Add fuzz/property tests for scheme characters in URL inputs"],"tags":["uri","parsing","scheme","validation"],"backgroundTag":"invalid-uri-scheme","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}