{"record":{"id":"090cb8c06f5ea367","repo":"tailscale/tailscale","slug":"csrf-request-denied-with-mismatched-origin-q-and","errorCode":null,"errorMessage":"CSRF request denied with mismatched Origin %q and Host %q","messagePattern":"CSRF request denied with mismatched Origin %q and Host %q","errorType":"http","errorClass":null,"httpStatus":403,"severity":"error","filePath":"client/web/web.go","lineNumber":292,"sourceCode":"\n\t\toriginHeader := r.Header.Get(\"Origin\")\n\t\tif originHeader == \"\" {\n\t\t\thttp.Error(w, \"CSRF request denied with no Origin header\", http.StatusForbidden)\n\t\t\treturn\n\t\t}\n\t\tparsedOrigin, err := url.Parse(originHeader)\n\t\tif err != nil {\n\t\t\thttp.Error(w, fmt.Sprintf(\"CSRF request denied with invalid Origin %q\", r.Header.Get(\"Origin\")), http.StatusForbidden)\n\t\t\treturn\n\t\t}\n\t\torigin := parsedOrigin.Host\n\t\tif origin == \"\" {\n\t\t\thttp.Error(w, \"CSRF request denied with no host in the Origin header\", http.StatusForbidden)\n\t\t\treturn\n\t\t}\n\n\t\tif origin != host {\n\t\t\thttp.Error(w, fmt.Sprintf(\"CSRF request denied with mismatched Origin %q and Host %q\", origin, host), http.StatusForbidden)\n\t\t\treturn\n\t\t}\n\n\t\th.ServeHTTP(w, r)\n\n\t})\n}\n\nfunc (s *Server) modeAPIHandler(mode ServerMode) (http.Handler, string) {\n\tswitch mode {\n\tcase LoginServerMode:\n\t\treturn http.HandlerFunc(s.serveLoginAPI), \"web_login_client_initialization\"\n\tcase ReadOnlyServerMode:\n\t\treturn http.HandlerFunc(s.serveLoginAPI), \"web_readonly_client_initialization\"\n\tcase ManageServerMode:\n\t\treturn http.HandlerFunc(s.serveAPI), \"web_client_initialization\"\n\tdefault: // invalid mode\n\t\tlog.Fatalf(\"invalid mode: %v\", mode)","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/tailscale/tailscale/blob/6e0912f97994f927632b34ae9e63b53d6516a6ac/client/web/web.go#L274-L310","documentation":"Returned as HTTP 403 by the CSRF middleware when the Origin host differs from the request Host (or the configured origin override). This is the actual cross-site detection; reverse proxies without the override set commonly trigger it.","triggerScenarios":"Thrown at client/web/web.go:292 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Access the web client via the same host as served (or the Tailscale IP)","Configure originOverride when reverse-proxying under a different hostname","Fix proxy header rewriting so Origin and Host agree"],"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-14T00:17:10.932Z"}