GitHub Advisoryadvisory · Go
GHSA-5p54-whvp-x327 AnyCable: Pusher REST API Does Not Verify Request Body MD5 Enabling Signed-Request Replay with Arbitrary Body
MEDIUM
Official page ↗
- Aliases
- CVE-2026-63405
- Ecosystem
- Go
- Packages
- github.com/anycable/anycable
- Severity
- Moderate
- CVSS vector
- CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N
- Weaknesses
- CWE-345
- Reviewed
- 2026-09-18
Affected packages
• Go github.com/anycable/anycable: < 1.6.15 → fixed in 1.6.15
Description
Summary
The Pusher-compatible REST API includes `body_md5` 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 `body_md5` from the URL query string (line 169) and includes it verbatim in `stringToSign` (line 175). It then verifies `HMAC(stringToSign, secret) == auth_signature`. After verification succeeds, `handleEvents` reads and parses `r.Body` (lines 201-212) without ever computing `md5(body)` and comparing it against the `body_md5` that was signed. The Pusher protocol specification explicitly requires the server to verify this digest to prevent body-substitution attacks. There is also no `auth_timestamp` staleness check, so replays are valid indefinitely.
PoC
1. Capture a legitimate signed POST to `/apps//events?auth_key=K&auth_timestamp=T&auth_version=1.0&body_md5=LEGIT_MD5&auth_signature=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 `body_md5` query parameter using a constant-time comparison before proceeding. Additionally, reject requests whose `auth_timestamp` is more than 600 seconds from the current time.
Related
Alias · CVE (1)
- CVE-2026-63405 AnyCable is a realtime server for reliable two-way communication that supports any backend. vulnerability
Weakness · CWE (1)
- CWE-345 Insufficient Verification of Data Authenticity weakness