mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #4441] [Bug]: Unauthenticated arbitrary memory read and write in Mooncake TCP transport data plane #1121
Labels
No labels
ascend
auto-closed
bug
bug
CI/Build
Common
documentation
enhancement
feature request
good first issue
help wanted
high priority
MetaX
nightly-failure
pull-request
PyTorch Backend
question
RFC
Roadmap
stale
Store
Tests
Transfer Engine
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/Mooncake#1121
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @yyymk on GitHub (Oct 1, 2026).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/4441
Bug Report
Summary
The TCP transport of mooncake-transfer-engine serves a raw memory access protocol on its data port without any authentication or address validation. Any host that can reach the port can read and write arbitrary memory of the engine process, including memory outside any registered buffer. Runtime-confirmed on mooncake-transfer-engine 0.3.11.post1. The fix in 0.3.13 (commit
a2933849417259e562fc9cbad63c618d464dfb2d) added address validation against registered buffers. Suggested severity: High, CVSS 8.8.Details
TcpTransport::install(src/transport/tcp_transport/tcp_transport.cpp) opens a data listener viafindAvailableTcpPort, which picks a random port from the documented default range 15000-17000 (GlobalConfig::rpc_min_port/rpc_max_portin include/config.h) and binds on all interfaces.The server side of the protocol is
ServerSession. The wire header is a plain C struct, not packed, so it is 24 bytes on the wire:In
ServerSession::readHeaderthe address field from the network is used directly as a local pointer:readBodyreceivessizebytes from the socket intoaddr + total_transferred_bytes_.writeBodysendssizebytes of process memory starting ataddrback to the peer. There is no peer authentication,addr/sizeare never checked against the local segment descriptor's registered buffers,sizeis unbounded, and the connection is persistent, so several requests can be pipelined over one connection.0.3.13 wires a
validateTcpAddresscallback into the session and rejects addresses outside registered buffers in both directions. That confines the primitive to registered memory; the port still has no peer authentication.PoC
Environment: Linux x86_64, Python 3.11,
pip install mooncake-transfer-engine==0.3.11.post1. Run both scripts on machines that can reach each other; use the victim host's real IP, not 127.0.0.1.Victim (registers a canary buffer, also allocates a second buffer it never registers):
Run it with
GLOG_logtostderr=1 MC_FORCE_TCP=1 python victim.py 2> victim.log, then read the data port from the log lineTcpTransport: listen on port <N>.Attacker:
Observed on 0.3.11.post1: both reads return the canaries byte for byte (RTT ~0.2 ms), both writes replace the buffer contents, and the victim process stays alive throughout. A control connection that connects and closes, and 100 bytes of garbage sent to the handshake RPC port, also leave the victim alive. A read or write against an unmapped address such as 0x10 does not kill the process: the kernel returns EFAULT to the socket call and the session aborts, so the demonstrated primitive is read/write of mapped memory, not a one-packet crash.
Impact
This is a missing-authorization issue (CWE-306) on the engine data plane. The attacker needs no credentials, only network reachability to the TCP data port of an engine process. Deployments running the TCP transport (hosts without an RDMA NIC, or
MC_FORCE_TCP=1) bind it on all interfaces by default; the port is trivially discoverable because it always falls in the documented 15000-17000 range.Confidentiality: full process memory disclosure. In an sglang or vLLM deployment the hosting process is the scheduler/EngineCore, so the KV cache including user prompts and context, Python heap objects, keys and pointer chains can be dumped. Integrity: an attacker-controlled write anywhere in the process, including memory outside registered buffers, gives data corruption up to code execution in the engine process. Availability: overwriting mapped memory corrupts the hosting engine process. Suggested CVSS:3.1 vector AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H (8.8). Affected: mooncake-transfer-engine <= 0.3.12.post1; patched in 0.3.13.
Before submitting...
@github-actions[bot] commented on GitHub (Oct 1, 2026):
Thanks for opening this issue, @yyymk!
133664083A maintainer will triage this when possible. To help us respond faster, please include:
Useful links: Documentation · Contributing guide
@he-yufeng commented on GitHub (Oct 2, 2026):
Took a look at where this stands on current main, since the report pins the vulnerable code exactly.
The unvalidated path the report describes is closed as of
a2933849(#2974, first shipped in v0.3.13). CurrentServerSession::readHeader(mooncake-transfer-engine/src/transport/tcp_transport/tcp_transport_session_impl.h) now runs the remote-suppliedaddr/sizethroughvalidate_addr_before touching any body, on both opcodes:validateTcpAddress(tcp_transport.cpp:301) requires[addr, addr+size)to be fully contained in one registered buffer of the local segment, with overflow checks on both the range and each buffer.kStatusAddrRejectedto v2 initiators, and returns without enteringreadBody/writeBody. v1 initiators see the connection close.So the "arbitrary process memory" part of the report does not reproduce against main or any v0.3.13+ tag: a peer can still reach the listener unauthenticated, but it can only read and write buffers the engine actually registered, which is the intended data-plane semantics of this protocol. Affected releases are the ≤0.3.12 line.
Two follow-ups worth the core team's call rather than mine:
Happy to help draft the advisory text if the team wants one.