curl · Report #3330839
CVE-2025-10148: predictable WebSocket mask
How it was found
No AI was involved.
Summary:
The curl WebSocket implementation generates a fixed masking key at the beginning of a connection an re-uses it for every frame:
- Generation of masking key
enc.maskinCurl_ws_accept: https://github.com/curl/curl/blob/455afa1de5182b95a5dcc988f18cdff584b95239/lib/ws.c#L1340 - Usage in
ws_enc_write_head: https://github.com/curl/curl/blob/455afa1de5182b95a5dcc988f18cdff584b95239/lib/ws.c#L879 - Usage in
ws_enc_write_payload: https://github.com/curl/curl/blob/455afa1de5182b95a5dcc988f18cdff584b95239/lib/ws.c#L930
RFC-6455 §5.3 states:
[...] The masking key is a 32-bit value chosen at random by the client. When preparing a masked frame, the client MUST pick a fresh masking key from the set of allowed 32-bit values. The masking key needs to be unpredictable; thus, the masking key MUST be derived from a strong source of entropy, and the masking key for a given frame MUST NOT make it simple for a server/proxy to predict the masking key for a subsequent frame. The unpredictability of the masking key is essential to prevent authors of malicious applications from selecting the bytes that appear on the wire. [...]
Because the same masking key is repeatedly used for every frame, it is trivial for an attacker to "guess" the masking key of all subsequent frames.
Affected version
All versions since WebSocket support was added.
Steps To Reproduce:
None
Supporting Material/References:
None
Impact
See "Security Considerations > Attacks On Infrastructure (Masking)" in RFC-6455 §10.3. Here a short excerpt:
[...] As this protocol was being developed, an experiment was conducted to demonstrate a class of attacks on proxies that led to the poisoning of caching proxies deployed in the wild [TALKING]. The general form of the attack was to establish a connection to a server under the "attacker's" control, perform an UPGRADE on the HTTP connection similar to what the WebSocket Protocol does to establish a connection, and subsequently send data over that UPGRADEd connection that looked like a GET request for a specific known resource (which in an attack would likely be something like a widely deployed script for tracking hits or a resource on an ad-serving network). The remote server would respond with something that looked like a response to the fake GET request, and this response would be cached by a nonzero percentage of deployed intermediaries, thus poisoning the cache. The net effect of this attack would be that if a user could be convinced to visit a website the attacker controlled, the attacker could potentially poison the cache for that user and other users behind the same cache and run malicious script on other origins, compromising the web security model. [...]