Sep 19, 2026·5 min read·16 visits
AnyCable's Pusher-compatible REST API failed to validate that the HTTP POST request body matched the signature-verified body_md5 parameter, enabling arbitrary message injection via request replays.
AnyCable is a real-time communication server. Prior to version 1.6.15, its Pusher-compatible REST API suffered from an authentication bypass vulnerability because it failed to verify that the request body matched the signature-validated body_md5 parameter. This allows attackers to perform replay attacks with modified body contents.
AnyCable is a high-performance, real-time communication server designed to handle WebSocket connections and broadcast messages across diverse application backends. To support seamless integration and migration from existing architectures, AnyCable provides a Pusher-compatible REST API endpoint. This compatibility layer allows backend applications to trigger events and query subscriber information using standard Pusher HTTP protocols.
Prior to version 1.6.15, the AnyCable server failed to validate the relationship between the HTTP request body and the signature parameters supplied in the query string. This structural omission is classified under CWE-345 (Insufficient Verification of Data Authenticity) and CWE-294 (Authentication Bypass by Capture-replay). The vulnerability is tracked under CVE-2026-63405.
This vulnerability allows unauthenticated network attackers to perform signature replay and inject arbitrary data payloads. Because the server only verified the cryptographic integrity of the query string parameters, the actual request body could be replaced without invalidating the authentication state. As a result, the server would broadcast modified message contents as if they originated from an authorized source.
The underlying flaw resides in the decouple of query-string cryptographic verification from request body content validation. The Pusher REST API protocol specifies five critical query parameters: auth_key, auth_timestamp, auth_version, body_md5, and auth_signature. The server validates that the auth_signature parameter is an HMAC-SHA256 signature calculated over the HTTP method, request path, and sorted query parameters.
In the vulnerable implementation, the cryptographic verification process succeeded if the signature matched the parameters, including body_md5. However, the server never computed the actual MD5 checksum of the incoming HTTP request body to compare it with the body_md5 parameter. The application implicitly assumed that signature validation over the query string guaranteed the integrity of the corresponding body.
Because of this assumption, there was no logical link binding the physical payload to the authenticated parameter. Furthermore, the server lacked validation for the auth_timestamp parameter. Without verifying that the timestamp fell within a reasonable threshold relative to the server time, the application permitted signatures to remain valid indefinitely, enabling permanent replay attacks.
The vulnerability was addressed in commit d2cbadec792f038f4695c84a65c0d957b0fde72c. The patch introduces two distinct validation layers: a timestamp drift verification and an MD5 payload verification step. In the original implementation, handleEvents consumed the request body stream directly from r.Body without prior checksum validation.
The updated Handler function in pusher/http.go now forces structural checks on HTTP methods, timestamp age, and body checksums before processing. Below is an excerpt of the corrected code path:
// Parse and validate the timestamp parameter
ts, err := strconv.ParseInt(authTimestamp, 10, 64)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
// Limit timestamp replay window to 600 seconds
if delta := time.Now().Unix() - ts; delta > authTimestampGracePeriod || delta < -authTimestampGracePeriod {
w.WriteHeader(http.StatusUnauthorized)
return
}
// Read body and verify MD5 checksum
if r.Method == http.MethodPost {
bodyMD5 := queryParams.Get("body_md5")
body, err = io.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusUnprocessableEntity)
return
}
actualMD5 := fmt.Sprintf("%x", md5.Sum(body))
if actualMD5 != bodyMD5 {
w.WriteHeader(http.StatusUnauthorized)
return
}
}This implementation closes the bypass vector by checking that the actualMD5 matches the signature-bound bodyMD5 parameter. If an attacker alters the body, the checksum test fails, and the request is rejected with an HTTP 401 Unauthorized status code.
Exploiting this flaw requires an attacker to intercept or obtain a single, valid, signed HTTP POST request directed to the Pusher-compatible API endpoint. Because signatures do not expire due to the lack of timestamp verification, a captured signature can be replayed at any subsequent time.
An attacker constructs a new HTTP POST request to /apps/:app_id/events using the exact query string parameters retrieved from the legitimate request. The attacker alters the POST request body, inserting arbitrary event data or control structures. Because the signature matches the parameters, the server validates the signature, skips body verification, and processes the malicious JSON payload, distributing the unauthorized event to active clients.
The CVSS v3.1 base score is assessed at 5.9 (Medium), characterized by the vector CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N. The severity is mitigated to Medium because an attacker must first intercept a valid API signature, representing a high-complexity requirement. However, once a signature is obtained, the integrity impact is high.
An attacker exploiting this vulnerability can broadcast unauthorized events, distribute phishing links, inject malicious client-side scripts, or manipulate application state transitions for all active WebSocket subscribers. The lack of tenant separation within the signed request means a compromised signature can affect any channel authorized under that key.
There is no recorded in-the-wild exploitation, and the EPSS score remains low at 0.00172. Nevertheless, because the exploit mechanics are straightforward once a signature is acquired, immediate mitigation is required for all exposed AnyCable endpoints.
The recommended remediation is to upgrade AnyCable to version 1.6.15 or later. This update enforces the necessary cryptographic check on the request body and enforces the 10-minute timestamp validation window. Developers using Go modules can apply the patch by executing:
go get github.com/anycable/anycable-go@v1.6.15When immediate patching is unfeasible, administrators should restrict access to the Pusher-compatible REST API routes (typically /apps/*/events) using network-level controls. Restricting source IP addresses to trusted backend application servers prevents unauthorized external entities from sending replayed requests directly to the AnyCable server.
Additionally, upstream reverse proxies should enforce maximum request body limits to mitigate potential denial-of-service risks. Since the patched code reads the entire request body into memory using io.ReadAll to compute the MD5 sum, limiting the allowable request size prevents resource exhaustion from oversized payloads.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
anycable-go AnyCable | < 1.6.15 | 1.6.15 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-345 / CWE-294 |
| Attack Vector | Network |
| CVSS v3.1 Score | 5.9 (Medium) |
| Exploit Status | None (No public exploit available) |
| EPSS Score | 0.00172 (0.17%) |
| CISA KEV Status | Not Listed |
The software does not sufficiently verify the authenticity of the data it receives, allowing an attacker to bypass authorization steps by replaying or modifying data.
CVE-2026-115878 (GHSA-gh9r-c94j-cmp5) is an arbitrary code execution vulnerability in the Stanford NLP Stanza Python library affecting version 1.14.0. The flaw originates from insecure deserialization of untrusted data (CWE-502) within the lemmatizer model loading pipeline in stanza/models/lemma/trainer.py. While Stanza utilizes PyTorch's weights_only=True flag during outer checkpoint loading, it embeds a gzip-compressed pickle byte stream inside the checkpoint dictionary. Because PyTorch treats raw bytes objects as safe primitives, the nested payload bypasses the outer allowlist and is subsequently passed to an unrestricted pickle.loads() call, enabling arbitrary code execution when loading a malicious model.
A code injection and SQL injection vulnerability exists in @enspirit/elo prior to version 1.0.1. When compiling expressions via the programmatic Abstract Syntax Tree (AST) API, the backend emitters for JavaScript, Ruby, Python, and PostgreSQL SQL fail to perform runtime type validation or lexical verification on AST node properties. Applications that construct or deserialize AST nodes from untrusted sources allow attackers to inject arbitrary code or SQL commands directly into the emitted target output.
CVE-2026-44266 (GHSA-7w38-ggh5-v542) is a code injection vulnerability in @enspirit/elo prior to version 1.0.1. The Ruby target compiler fails to escape the hash character (#) when emitting double-quoted Ruby string literals and subtype constraint failure labels. An attacker who supplies crafted Elo expressions to an application compiling and executing Ruby output achieves arbitrary code execution.
CVE-2026-44267 is a sandbox escape and code injection vulnerability in @enspirit/elo prior to version 1.0.1. Due to unrestricted member access transformation in the compiler pipeline, plain Elo expression strings can traverse JavaScript object prototypes via .constructor.constructor to access the host runtime Function constructor. This allows attackers supplying untrusted Elo expressions to execute arbitrary JavaScript in Node.js server environments or client browser contexts.
CVE-2026-62374 (GHSA-f9j6-8p6x-r9j6) is a verification bypass vulnerability in the OpenWallet Foundation SD JWT JS library (@sd-jwt/core and @sd-jwt/decode versions 0.19.0 and earlier). Due to permissive UTF-8 decoding and the omission of mandatory reference checks during presentation verification, tampered or unreferenced disclosures are silently dropped rather than rejected. This deviates from RFC 9901 §7.1 requirements and allows attackers to execute silent claim-set reduction attacks against relying parties.
An interpretation conflict in Bytebase DBHub (< 0.22.6) allows attackers to bypass read-only SQL query restrictions when connected to MySQL or MariaDB instances. Because DBHub's custom SQL tokenizer treats any '--' sequence as a comment, whereas MySQL and MariaDB require trailing whitespace or a control character, crafted queries containing '--' immediately followed by non-whitespace characters allow stacked destructive SQL statements to execute on connections configured as read-only.