{"record":{"id":"79eaa238a28fe450","repo":"tailscale/tailscale","slug":"disallowed-target-host-q-in-redirect-url-q","errorCode":null,"errorMessage":"disallowed target host %q in redirect URL %q","messagePattern":"disallowed target host %q in redirect URL %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tsweb/tsweb.go","lineNumber":1013,"sourceCode":"\t}\n\n\turl, err := url.Parse(urlStr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid redirect URL %q: %w\", urlStr, err)\n\t}\n\t// Redirects to self are always allowed. A self redirect must\n\t// start with url.Path, all prior URL sections must be empty.\n\tisSelfRedirect := url.Scheme == \"\" && url.Opaque == \"\" && url.User == nil && url.Host == \"\"\n\tif isSelfRedirect {\n\t\treturn url, nil\n\t}\n\tfor _, allowed := range allowedHosts {\n\t\tif strings.EqualFold(allowed, url.Hostname()) {\n\t\t\treturn url, nil\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"disallowed target host %q in redirect URL %q\", url.Hostname(), urlStr)\n}\n\n// hasSafeRedirectPrefix reports whether url starts with a slash, or\n// one of the case-insensitive strings \"http://\" or \"https://\".\nfunc hasSafeRedirectPrefix(url string) bool {\n\tif len(url) >= 1 && url[0] == '/' {\n\t\treturn true\n\t}\n\tconst http = \"http://\"\n\tif len(url) >= len(http) && strings.EqualFold(url[:len(http)], http) {\n\t\treturn true\n\t}\n\tconst https = \"https://\"\n\tif len(url) >= len(https) && strings.EqualFold(url[:len(https)], https) {\n\t\treturn true\n\t}\n\treturn false\n}","sourceCodeStart":995,"sourceCodeEnd":1031,"githubUrl":"https://github.com/tailscale/tailscale/blob/6e0912f97994f927632b34ae9e63b53d6516a6ac/tsweb/tsweb.go#L995-L1031","documentation":"Raised when a parsed redirect URL is well-formed but its hostname is not in allowedHosts (and it is not a same-host self redirect). This is the open-redirect protection: the redirect would send users to a host the application has not explicitly approved.","triggerScenarios":"Thrown at tsweb/tsweb.go:1013 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Add the intended target host to the allowedHosts list if the redirect is legitimate","Otherwise treat as an open-redirect attempt and reject the request","Prefer relative/self redirects to avoid expanding the allow-list"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"6e0912f97994f927632b34ae9e63b53d6516a6ac","analyzedAt":"2026-08-18T08:17:25.280Z","contentChangedAt":"2026-08-18T08:17:25.280Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}