Aug 25, 2026·6 min read·1 visit
Gorilla WebSocket used math/rand instead of crypto/rand for masking keys, allowing attackers to predict key sequences and construct payloads that bypass proxy controls to perform request smuggling or cache poisoning.
A security vulnerability in the github.com/gorilla/websocket Go library allows remote attackers to predict client-to-server frame masking keys. This occurs because the library generates 32-bit mask keys using Go's non-cryptographically secure pseudo-random number generator (math/rand). Predicting these keys enables adversaries to bypass proxy-based security protections, facilitating HTTP request smuggling and cache poisoning attacks.
The vulnerability GHSA-W67G-5RQW-F597 targets the Go-based library github.com/gorilla/websocket, which is a widely utilized implementation of the WebSocket protocol. In WebSocket architectures, client-to-server frames must be masked using a 32-bit key to prevent intermediate HTTP proxies from misinterpreting raw TCP stream data as independent HTTP requests. This defensive mechanism is mandated by RFC 6455 to prevent request manipulation by untrusted client payloads.\n\nThe vulnerability resides in the implementation of the mask key generator, which relied on Go's standard library math/rand package prior to version 1.5.3. Because math/rand is a pseudo-random number generator designed for speed rather than cryptographic security, its outputs are fully deterministic once the seed or internal state is recovered. This design flaw exposes applications utilizing the client package to network-based attacks.\n\nAn attacker who is able to predict the sequence of generated mask keys can structure malicious payloads that, when XORed with the predicted mask key by the client, produce valid, unmasked HTTP request streams on the wire. This capability enables adversaries to conduct request smuggling, session hijacking, or cache poisoning on intermediate proxies that inspect the TCP connection. The vulnerability presents an integrity and confidentiality threat to communication paths crossing HTTP-aware network infrastructure.
The root cause of this vulnerability lies in the choice of PRNG used to generate the 32-bit frame masking keys. The math/rand package in Go employs an additive lagged Fibonacci generator with a recurrence relation defined by the state size of 607 64-bit integers. This mathematical design makes the generator vulnerable to complete state recovery once a sufficient quantity of consecutive outputs is observed by an attacker.\n\nUnder RFC 6455, every client frame must use a newly generated 32-bit key. Because the key space is small and the sequence generation is linear, an attacker observing approximately 1,214 consecutive 32-bit masking keys can reconstruct the 607-element internal state array of the generator. Alternatively, if the host application seeded the generator with a predictable value such as the system timestamp at startup, the initial seed can be brute-forced remotely.\n\nOnce the state is recovered, all future mask values produced by the client connection become deterministic. The attacker can predict the exact 32-bit XOR key that the client library will apply to the next outgoing frame. Because masking is a simple bitwise XOR operation, this predictability breaks the security assumptions of the WebSocket masking protocol, allowing the creation of specific traffic patterns that are interpreted differently by the endpoint and transit proxies.
In versions of gorilla/websocket prior to 1.5.3, the mask key was generated in the newMaskKey function located within conn.go. The implementation invoked rand.Uint32() directly from the standard math/rand package. This function extracts pseudo-random bits from the default shared generator source.\n\nThe vulnerable code path is structured as follows:\n\ngo\n// Vulnerable implementation in gorilla/websocket/conn.go\nfunc newMaskKey() [4]byte {\n\tn := rand.Uint32() // Non-cryptographic PRNG\n\treturn [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)}\n}\n\n\nThe remediation commit d67f41855da42d7bccd9ef050c49f7e54e783b95 replaced this implementation with a secure read from crypto/rand. It introduced an unexported package-level variable maskRand initialized to rand.Reader, ensuring that the entropy is drawn from the operating system's cryptographic provider.\n\nThe patched code path is implemented as follows:\n\ngo\n// Patched implementation in gorilla/websocket/conn.go\nvar maskRand = rand.Reader // Defaults to crypto/rand.Reader\n\nfunc newMaskKey() [4]byte {\n\tvar k [4]byte\n\t_, _ = io.ReadFull(maskRand, k[:]) // Secure cryptographic read\n\treturn k\n}\n\n\nBy transitioning to crypto/rand.Reader, the library utilizes operating-system level entropy sources (such as /dev/urandom or getrandom system calls on Linux). This guarantees that each masking key is cryptographically secure and independent of prior keys, neutralizing state-reconstruction and seed-prediction vectors.
Exploitation of GHSA-W67G-5RQW-F597 requires the attacker to predict the masking key that the client library will assign to a future frame. To achieve this, the attacker first synchronizes with the client's PRNG state by sending multiple messages and capturing the output over the network. By reversing the XOR operation with known cleartext payloads, the attacker isolates the sequence of 32-bit mask keys.\n\nWith the PRNG state reconstructed, the attacker designs an HTTP request payload R intended to poison an intermediary HTTP cache. The attacker then calculates the malicious payload P by performing a bitwise XOR of R with the predicted mask key M. This calculated payload P is sent through the client WebSocket interface.\n\nmermaid\ngraph LR\n subgraph Attacker Infrastructure\n A["Calculate Payload: P = R XOR M"]\n end\n subgraph Client System\n B["WebSocket Client (Vulnerable)"]\n C["Apply Mask: Transmitted = P XOR M"]\n end\n subgraph Transit Network\n D["Intermediary Proxy (Reads Plaintext R)"]\n end\n subgraph Target Infrastructure\n E["Target Web Server / Cache"]\n end\n A --> B\n B --> C\n C -->|Sends Plaintext R| D\n D -->|Cache Poisoning / Smuggling| E\n\n\nWhen the client library prepares the frame for transmission, it applies the mask key M to the payload P. Because (R XOR M) XOR M = R, the actual bytes transmitted over the physical medium correspond exactly to the cleartext HTTP request R. An intermediate proxy inspecting the TCP flow reads R as a legitimate, separate HTTP transaction, leading to cache poisoning or request smuggling.
The security impact of predictable masking keys is primarily centered on the integrity of network proxy filters. It does not lead directly to remote code execution on the client or server, nor does it allow the exposure of local system memory. Instead, it systematically undermines the proxy-abuse protections designed into the RFC 6455 specification.\n\nIn environments where client traffic traverses corporate firewalls, reverse proxies, or content delivery networks (CDNs), the ability to bypass WebSocket frame isolation allows request smuggling. Attackers can inject arbitrary headers or split HTTP connections, potentially accessing unauthorized endpoints or poisoning downstream caches for other users. The CVSS score for this vulnerability is 6.9, reflecting network-accessible low integrity and confidentiality impacts.\n\nDue to the lack of a registered CVE identifier, this vulnerability does not appear in standard vulnerability databases such as the CISA KEV or the EPSS scoring registry. The exploit maturity is classified as proof-of-concept, as the algorithms for predicting lagged Fibonacci generators are well understood and widely documented, though specific, automated toolkits targeting this library in the wild are not currently observed.
Remediation requires updating the github.com/gorilla/websocket dependency to version 1.5.3 or higher. This update changes the masking key generator to use cryptographically secure random bytes, preventing any predictability-based exploit attempts.\n\nTo apply the update using Go modules, execute the following commands in the project directory:\n\nbash\ngo get github.com/gorilla/websocket@v1.5.3\ngo mod tidy\n\n\nFor systems where upgrading the dependency is not immediately feasible, network-level workarounds can mitigate the risk. Enforcing transport layer security (TLS) for all WebSocket connections (using wss:// instead of ws://) prevents intermediate proxies from inspecting or parsing the payload stream. Since the data is encrypted in transit before reaching any proxies, the proxy cannot interpret the unmasked stream as a separate HTTP request.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
websocket gorilla | < 1.5.3 | 1.5.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-338 |
| Attack Vector | Network |
| CVSS Score | 6.9 (Medium) |
| EPSS Score | N/A (No registered CVE) |
| Impact | HTTP Request Smuggling, Cache Poisoning |
| Exploit Status | Proof-of-Concept |
| KEV Status | Not Listed |
The product uses a pseudo-random number generator (PRNG) in a security context, but the generator's algorithm is not cryptographically strong, making its output predictable.
Prior to version 5.0.8, django CMS fails to respect dynamically declared Vary HTTP headers in its internal page cache. This allows remote attackers to bypass authorization, leak sensitive information across user sessions, or poison the page cache by sending requests with custom headers.
MHSanaei 3X-UI is a web control panel for managing Xray-core servers. In versions prior to 3.3.1, an authenticated administrator can abuse database import functions or raw template config fields to overwrite or append to arbitrary files on the host filesystem. This is achieved by altering the Xray log configuration variables to target system files, leveraging logging components to inject payloads.
Cloudreve is vulnerable to an incorrect authorization bypass. When listing files, Cloudreve returns a context_hint (represented as a UUID) to the client. If this context hint is replayed on the /file/url or /file/thumb routes, Cloudreve's database file system caches the shareNavigatorState containing the loaded share root. Within the cache lifetime (TTL of 300 seconds), if the user re-requests the same file with the cached hint, the system restores the state and completely bypasses the root security checks (which validate share expiration, remaining download limits, owner status, and passwords). This allows unauthorized users to continue generating signed file URLs and downloading files even after a share has been deleted, has expired, or has reached its download limit.
A path traversal vulnerability exists in Cloudreve's remote download workflow, where improper sanitization of file paths returned by configured remote downloaders (such as aria2) allows authenticated users to write files outside the designated target folder.
An integer overflow vulnerability exists in the HTTP/1.x chunked encoding parser of the vibeio-http library. The flaw is caused by unchecked integer addition when calculating the total buffer size required for processing parsed chunk lengths. By sending a maliciously crafted HTTP request containing an extremely large chunk size, an unauthenticated remote attacker can trigger a runtime panic, leading to complete denial of service.
netfoil, an allowlist-based DNS proxy, failed to sanitize ALPN fields parsed from untrusted DNS-over-HTTPS (DoH) HTTPS Resource Records. This allowed attackers to inject ANSI escape sequences into log files or trigger Denial of Service (DoS) via uncontrolled memory allocations.