{"record":{"id":"fce7217dcde46ca0","repo":"aio-libs/aiohttp","slug":"invalid-challenge-response","errorCode":null,"errorMessage":"Invalid challenge response","messagePattern":"Invalid challenge response","errorType":"http","errorClass":"WSServerHandshakeError","httpStatus":null,"severity":"error","filePath":"aiohttp/client.py","lineNumber":1131,"sourceCode":"                    message=\"Invalid upgrade header\",\n                    status=resp.status,\n                    headers=resp.headers,\n                )\n\n            if not resp._upgraded:\n                raise WSServerHandshakeError(\n                    resp.request_info,\n                    resp.history,\n                    message=\"Invalid connection header\",\n                    status=resp.status,\n                    headers=resp.headers,\n                )\n\n            # key calculation\n            r_key = resp.headers.get(hdrs.SEC_WEBSOCKET_ACCEPT, \"\")\n            match = base64.b64encode(hashlib.sha1(sec_key + WS_KEY).digest()).decode()\n            if r_key != match:\n                raise WSServerHandshakeError(\n                    resp.request_info,\n                    resp.history,\n                    message=\"Invalid challenge response\",\n                    status=resp.status,\n                    headers=resp.headers,\n                )\n\n            # websocket protocol\n            protocol = None\n            if protocols and hdrs.SEC_WEBSOCKET_PROTOCOL in resp.headers:\n                resp_protocols = [\n                    proto.strip()\n                    for proto in resp.headers[hdrs.SEC_WEBSOCKET_PROTOCOL].split(\",\")\n                ]\n\n                for proto in resp_protocols:\n                    if proto in protocols:\n                        protocol = proto","sourceCodeStart":1113,"sourceCodeEnd":1149,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/client.py#L1113-L1149","documentation":"Raised as WSServerHandshakeError when the SEC_WEBSOCKET_ACCEPT response header does not equal base64(sha1(sec_key + WS_KEY)). This proves the server did not follow the RFC 6455 opening-handshake derivation; without it aiohttp cannot trust that the peer actually speaks WebSocket.","triggerScenarios":"Server returns 101 with correct Upgrade/Connection but a wrong or missing Sec-WebSocket-Accept value. r_key != computed match. Happens with non-RFC-compliant servers, some transparent proxies, or when the request's Sec-WebSocket-Key was modified in flight.","commonSituations":"Custom server that doesn't compute the accept hash. Proxy that rewrites handshake headers. Anti-DDoS/WAF that mangles Sec-WebSocket-* headers. Mismatched WebSocket subprotocol libraries.","solutions":["Confirm the server implements RFC 6455 Sec-WebSocket-Accept derivation (sha1(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'), base64).","Inspect the .headers on the caught WSServerHandshakeError to compare the returned accept with the expected one.","Remove intermediaries that rewrite Sec-WebSocket-* headers, or move to a direct wss:// connection."],"exampleFix":"// before\n# server returns Sec-WebSocket-Accept that does not match the derivation\nawait session.ws_connect('wss://x')  # raises Invalid challenge response\n// after\n# fix the server to compute base64(sha1(sec_websocket_key + GUID))","handlingStrategy":"try-catch","validationCode":"import hashlib, base64\n\nGUID = b'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'\n\ndef expected_accept(sec_key: str) -> str:\n    return base64.b64encode(hashlib.sha1(sec_key.encode() + GUID).digest()).decode()\n\n# Use to verify the server you are integrating against.","typeGuard":"import hashlib, base64\n\ndef is_valid_accept(sec_key: str, accept_header: str) -> bool:\n    expected = base64.b64encode(hashlib.sha1(sec_key.encode() + b'258EAFA5-E914-47DA-95CA-C5AB0DC85B11').digest()).decode()\n    return accept_header == expected","tryCatchPattern":"from aiohttp import WSServerHandshakeError\n\ntry:\n    ws = await session.ws_connect(url)\nexcept WSServerHandshakeError as e:\n    if e.message == 'Invalid challenge response':\n        # server did not follow RFC 6455; cannot interoperate\n        raise\n    raise","preventionTips":["Use a compliant WebSocket server library for the peer.","Remove proxies/WAFs that mangle Sec-WebSocket-* headers.","Add an integration test that asserts the accept hash round-trips."],"tags":["websocket","handshake","security","rfc6455"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}