{"record":{"id":"264992248cb5cf4d","repo":"juanfont/headscale","slug":"s-confirm-form-no-value-in-csrf-input","errorCode":null,"errorMessage":"%s confirm form: no value in CSRF input","messagePattern":"(.+?) confirm form: no value in CSRF input","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"integration/scenario.go","lineNumber":1289,"sourceCode":"\tif !ok {\n\t\treturn \"\", nil, fmt.Errorf(\"%s confirm form: no CSRF input\", hostname) //nolint:err113\n\t}\n\n\ttagStart := strings.LastIndex(before, \"<input\")\n\tif tagStart == -1 {\n\t\treturn \"\", nil, fmt.Errorf(\"%s confirm form: no input tag for CSRF\", hostname) //nolint:err113\n\t}\n\n\ttagEnd := strings.Index(htmlBody[tagStart:], \">\")\n\tif tagEnd == -1 {\n\t\treturn \"\", nil, fmt.Errorf(\"%s confirm form: unterminated input tag\", hostname) //nolint:err113\n\t}\n\n\tinputTag := htmlBody[tagStart : tagStart+tagEnd+1]\n\n\tvalIdx := strings.Index(inputTag, `value=\"`)\n\tif valIdx == -1 {\n\t\treturn \"\", nil, fmt.Errorf(\"%s confirm form: no value in CSRF input\", hostname) //nolint:err113\n\t}\n\n\tvalStart := valIdx + len(`value=\"`)\n\tvalEnd := strings.Index(inputTag[valStart:], `\"`)\n\tcsrfToken := inputTag[valStart : valStart+valEnd]\n\n\t// Build the absolute POST URL from the response's request URL.\n\tbase := prevResp.Request.URL\n\tconfirmURL := &url.URL{\n\t\tScheme: base.Scheme,\n\t\tHost:   base.Host,\n\t\tPath:   formAction,\n\t}\n\n\tlog.Printf(\"%s auto-submitting confirm form: %s\", hostname, confirmURL)\n\n\tformData := url.Values{\n\t\t\"headscale_register_confirm\": {csrfToken},","sourceCodeStart":1271,"sourceCodeEnd":1307,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/integration/scenario.go#L1271-L1307","documentation":"The CSRF `<input>` tag was captured whole, but it contains no `value=\"` attribute, so there is no token to submit with the confirm POST. The template is expected to render attributes in name-type-value order; a missing value means the form was rendered without a token.","triggerScenarios":"`strings.Index(inputTag, \"value=\\\"\")` returns -1 on the captured tag. Occurs when the hidden input is rendered with `value=''`, no value at all, or a differently ordered/quoted attribute so the slice from `<input` to `>` missed it.","commonSituations":"Template change altering attribute order or quoting (e.g. value='...' with single quotes); server renders an empty token because the registration session expired; HTML attribute escaping mangles the value attribute.","solutions":["Print the captured `inputTag` to see exactly how the value attribute is rendered.","Align the parser with the template's current attribute order/quoting.","Use x/net/html to read form values robustly instead of substring matching."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Log the captured input tag whenever extraction fails.","Handle both quote styles (`value=\\\"` and `value='`) if you keep scraping.","Use html.Parse + form traversal to read values regardless of attribute order."],"tags":["html-parsing","integration","csrf"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}