CVE-2026-63405: AnyCable: Pusher REST API Does Not Verify Request Body MD5 Enabling Signed-Request Replay with Arbitrary Body

Published Sep 18, 2026
·
Updated

Summary The Pusher-compatible REST API includes bodymd5 in the HMAC signature string but never computes or verifies the MD5 of the received HTTP body, allowing anyone who observes a signed request to replay it with an entirely different body.

Details In pusher/http.go, the Handler function extracts bodymd5 from the URL query string (line 169) and includes it verbatim in stringToSign (line 175). It then verifies HMAC(stringToSign, secret) == authsignature. After verification succeeds, handleEvents reads and parses r.Body (lines 201-212) without ever computing md5(body) and comparing it against the bodymd5 that was signed. The Pusher protocol specification explicitly requires the server to verify this digest to prevent body-substitution attacks. There is also no authtimestamp staleness check, so replays are valid indefinitely.

PoC 1. Capture a legitimate signed POST to /apps/<appid>/events?authkey=K&authtimestamp=T&authversion=1.0&bodymd5=LEGITMD5&authsignature=SIG carrying body {"name":"safe-event","channel":"ch","data":"..."} (e.g., from TLS-terminating load-balancer logs). 2. Send a new request with the same query string parameters but a different body: {"name":"injected-event","channel":"admin","data":"malicious-payload"} 3. The server accepts the request (HMAC over stringToSign matches the original) and broadcasts the injected event to all subscribers of admin.

Impact An attacker who can read any single signed Pusher API request (from logs, a shared proxy, or a network tap) can broadcast arbitrary events to any channel indefinitely, potentially forging server-side events, corrupting application state, or delivering phishing messages to WebSocket clients.

Fix After reading r.Body, compute hex(md5(body)) and compare it to the bodymd5 query parameter using a constant-time comparison before proceeding. Additionally, reject requests whose authtimestamp is more than 600 seconds from the current time.

Other sources

AnyCable is a realtime server for reliable two-way communication that supports any backend. Prior to 1.6.15, the Pusher-compatible REST API in pusher/http.go includes the caller-supplied bodymd5 value in the HMAC input but does not calculate the digest of the received request body or compare it with the signed value. An attacker who obtains a legitimate signed POST request can retain its query parameters and authsignature while replacing the body, causing Handler and handleEvents to accept and broadcast attacker-selected event content. The absence of an authtimestamp freshness check also allows the captured signature to be replayed indefinitely. This can forge server-side events, modify application state, or deliver attacker-controlled messages to WebSocket clients within the signed request's application context. This issue is fixed in version 1.6.15.

MITRE

Affected Software

2 affected componentsFixes available
AnyCable AnyCable<1.6.15
go/github.com/anycable/anycable<=1.6.14
1.6.15

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade go/github.com/anycable/anycable to a version that resolves this vulnerability.

    Fixed in 1.6.15
  2. Upgrade

    Upgrade AnyCable (Pusher-compatible REST API) to a version that resolves this vulnerability.

    Fixed in 1.6.15
  3. Configuration

    In the Handler logic, before verifying/processing the request, reject requests when `auth_timestamp` is more than 600 seconds from the current time (implement the staleness check).

    Pusher REST API handler (pusher/http.go) auth_timestamp freshness validation = reject if auth_timestamp is more than 600 seconds from the current time
  4. Configuration

    In the Handler logic, after reading `r.Body`, compute `hex(md5(body))` and constant-time compare it against the `body_md5` query parameter; only proceed if the comparison succeeds.

    Pusher REST API handler (pusher/http.go) body_md5 verification = compute hex(md5(body)) after reading r.Body; constant-time compare to body_md5 query parameter before proceeding

Event History

Sep 18, 2026
CVE Published
via MITRE·04:47 PM
Data Sourced
via MITRE·04:47 PM
DescriptionSeverityWeakness
Advisory Published
via GitHub·05:16 PM
Data Sourced
via GitHub·05:16 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Who is exposed to this issue?

AnyCable deployments using the Pusher-compatible REST API are exposed if they run a version prior to 1.6.15. WebSocket clients in the application context associated with a captured signed request may receive attacker-controlled events.

2

What does an attacker need to exploit it?

The attacker needs to obtain a legitimate signed POST request. They can then keep its query parameters and auth_signature while replacing the request body with attacker-selected event content.

3

Does a captured request expire?

No. The affected implementation does not check auth_timestamp freshness, so a captured signature can be replayed indefinitely.

4

What is the remediation?

Upgrade AnyCable to version 1.6.15, which fixes the issue.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203