{"record":{"id":"eafe7dfe0606b155","repo":"gravitational/teleport","slug":"unexpected-nil-response-from-getassertion","errorCode":null,"errorMessage":"unexpected nil response from GetAssertion","messagePattern":"unexpected nil response from GetAssertion","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/auth/webauthnwin/webauthn_windows.go","lineNumber":141,"sourceCode":"\t)\n\n\tif n.webauthnAPIVersion < int(in.opts.dwVersion) {\n\t\tconst legacyVersion = 5\n\t\tin.opts.dwVersion = legacyVersion\n\t\tlogger.DebugContext(context.Background(),\n\t\t\t\"WebAuthn.dll too old, falling back to legacy version\",\n\t\t\t\"api_version\", n.webauthnAPIVersion,\n\t\t\t\"legacy_version\", in.opts.dwVersion,\n\t\t)\n\t}\n\n\tvar out *webauthnAssertion\n\tret, err := webAuthNAuthenticatorGetAssertion(hwnd, in.rpID, in.clientData, in.opts, &out)\n\tif ret != 0 {\n\t\treturn nil, trace.Wrap(getErrorNameOrLastErr(ret, err))\n\t}\n\tif out == nil {\n\t\treturn nil, errors.New(\"unexpected nil response from GetAssertion\")\n\t}\n\n\t// Note that we need to copy bytes out of `out` if we want to free object.\n\t// That's why bytesFromCBytes is used.\n\tdefer freeAssertion(out)\n\n\tauthData := bytesFromCBytes(out.cbAuthenticatorData, out.pbAuthenticatorData)\n\tsignature := bytesFromCBytes(out.cbSignature, out.pbSignature)\n\tuserID := bytesFromCBytes(out.cbUserID, out.pbUserID)\n\tcredential := bytesFromCBytes(out.Credential.cbID, out.Credential.pbID)\n\tcredType := windows.UTF16PtrToString(out.Credential.pwszCredentialType)\n\n\treturn &wantypes.CredentialAssertionResponse{\n\t\tPublicKeyCredential: wantypes.PublicKeyCredential{\n\t\t\tRawID: credential,\n\t\t\tCredential: wantypes.Credential{\n\t\t\t\tID:   base64.RawURLEncoding.EncodeToString(credential),\n\t\t\t\tType: credType,","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/lib/auth/webauthnwin/webauthn_windows.go#L123-L159","documentation":"GetAssertion calls the Windows webauthn.dll entry point WebAuthNAuthenticatorGetAssertion, which reports success (ret == 0) but left the out *webauthnAssertion pointer nil. The Go wrapper treats this as an invariant violation: the Win32 API promised a result but produced none, so there is no assertion to parse and the call aborts with this plain error instead of dereferencing nil.","triggerScenarios":"Calling nativeImpl.GetAssertion (used during WebAuthn login/ceremony in tsh and Teleport on Windows) when WebAuthNAuthenticatorGetAssertion returns HR_SUCCESS (0) but does not populate the WEBAUTHN_ASSERTION output struct — a defective or partially functional webauthn.dll / Windows Hello stack.","commonSituations":"Older or corrupted Windows builds with a buggy webauthn.dll; Windows Hello or the platform authenticator in a broken state (TPM faults, stale credentials); running on non-standard Windows editions or virtualized environments where the API succeeds spuriously.","solutions":["Retry the WebAuthn ceremony once — transient Hello/TPM issues can clear the condition.","Update Windows (webauthn.dll fixes ship in cumulative updates) and verify Windows Hello is set up and working in Settings > Accounts > Sign-in options.","Fall back to another authenticator (hardware security key or non-native WebAuthn path) instead of the Windows-native implementation.","Report to Teleport if reproducible on a supported Windows version; the code path expects a non-nil assertion on success."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Before starting the ceremony, verify the native WebAuthn stack is usable:\nif !native.HasCompileSupport() || !native.IsAvailable() {\n    // fall back to non-native authenticator path\n}","typeGuard":"func assertionAvailable(out *webauthnAssertion) bool { return out != nil }","tryCatchPattern":"resp, err := native.GetAssertion(origin, req)\nif err != nil {\n    if strings.Contains(err.Error(), \"unexpected nil response\") {\n        // fall back to hardware key / retry once\n    }\n    return trace.Wrap(err)\n}","preventionTips":["Keep Windows fully updated so webauthn.dll is current.","Verify Windows Hello is enrolled before passwordless ceremonies.","Fall back to hardware security keys on virtualized/unsupported Windows installs."],"tags":["windows","webauthn","cgo","nil-pointer"],"backgroundTag":"webauthn-nil-response","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}