security-advisories/2023-11-21-0-websocket-compression-dos.md
When using the KJ HTTP library with WebSocket compression enabled, a buffer underrun can be caused by a remote peer. The underrun always writes a constant value that is not attacker-controlled, likely resulting in a crash, enabling a remote denial-of-service attack.
Most Cap'n Proto and KJ users are unlikely to have this functionality enabled and so unlikely to be affected. We suspect only the Cloudflare Workers Runtime is affected.
Cloudflare Workers team
2023-11-21
CVE-2023-48230
HttpClientSettings or HttpServerSettings. We suspect no one uses this setting today except for Cloudflare Workers.{ 0x00, 0x00, 0xFF, 0xFF }. Because this string is not controlled by the attacker, we suspect it is unlikely that remote code execution is possible. However, it cannot be ruled out.C++ fix:
master (1.x) branch: e7f22da9c01286a2b0e1e5fbdf3ec9ab3aa128ffv2 branch: 75c5c1499aa6e7690b741204ff9af91cce526c59KJ is a C++ toolkit library that evolved along with the Cap'n Proto C++ implementation. While it originally contained only a few utilities used by Cap'n Proto itself, it has grown over time with quite a few features. One of the larger features is an HTTP/1.1 implementation, complete with WebSocket support. KJ's HTTP library is used by the Cloudflare Workers runtime.
In 2022, the Cloudflare Workers team added support for the WebSocket compression extension to KJ HTTP. The feature is enabled by default for Workers whose compatibility date is 2023-08-15 or later. That is, this feature only became enabled by default recently, and only for new Workers or Workers that updated their compatibility date.
A bug in the code caused it to improperly handle the case where compression had been negotiated, but a particular message received from the peer was not compressed, i.e. did not have the compression bit set in the frame header. The code would correctly allocate buffer space for a non-compressed message. However, later on, the code incorrectly treated the message as compressed, and therefore attempted to prefix it with the constant string { 0x00, 0x00, 0xFF, 0xFF } which must be added before passing the bytes to zlib. Since the buffer was not allocated with space for these bytes, they would be written into the four bytes preceding the buffer instead.
In most cases, this had the effect of overwriting state maintained by the memory allocator, causing a subsequent memory allocation operation to crash.
Because the bytes are always a constant string, not attacker-controlled, it seems difficult to leverage this overrun to achieve code execution. However, we cannot rule out an excessively clever exploit.
The bug was discovered when it was triggered in production, and was quickly patched. The occurrences in production were benign, not an attack. It is normal for some WebSocket implementations to negotiate compression but then opportunistically skip it when it doesn't help, which would trigger the bug.