mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #4478] [Bug]: Unauthenticated disk replica erasure and object deletion via EvictDiskReplica in Mooncake Store Master #1136
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#1136
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 5, 2026).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/4478
Bug Report
Summary
Mooncake Store Master serves
EvictDiskReplicaandBatchEvictDiskReplicaon its unauthenticated RPC port (default 0.0.0.0:50051). When called withreplica_type=DISK, the master erases the disk-tier replica metadata of any object without checking caller ownership, tenant, or lease — while the same function'sLOCAL_DISKbranch does filter by client_id. An unauthenticated peer erases the persistence-tier replica of any key, and when the disk replica is the object's only remaining replica, the whole object is deleted. Runtime-confirmed on the master binary shipped in the 0.3.13.post1 wheel (latest release, with the documented--root_fs_dirpersistence configuration); no fix available. Suggested severity: High, CVSS 9.1.Details
In
MasterService::EvictDiskReplica(mooncake-store/src/master_service.cpp) thereplica_typeselects the branch:The DISK branch has no ownership, lease, or tenant check of any kind — the request carries a client_id that is never consulted for this branch. The LOCAL_DISK branch of the same function does compare the replica's client_id, showing the asymmetry is not an intended trust decision. After erasure,
if (!metadata.IsValid()) accessor.Erase()deletes the whole object once no valid replica remains.Disk replicas are created by the master's own storage backend in the documented persistence configuration (
--root_fs_dir): after a memory Put, the client'sPutToLocalFilepath stores the object and commits it withPutEnd(ReplicaType::DISK). Deployments running with--root_fs_dir(the persistence/HA form) are therefore affected;BatchEvictDiskReplicaloops the same path over a key list.This is distinct from the pending Remove-family report and from CVE-2026-96762: different method, different asset (persistence-tier replica metadata vs object metadata or segment registration), and no force flag involved.
PoC
Environment: Linux, the 0.3.13.post1 wheel's
mooncake_masterstarted with--rpc_address=0.0.0.0 --rpc_port=50051 --root_fs_dir=<dir> --enable_offload, and a victim store client that has put objects (each object then shows replicas['MEMORY','DISK']viaget_replica_desc). The attacker forges coro_rpc frames (20-byte header, magic=21; struct_pack body: UUID client_id, length-prefixed key, tenant, u32 replica_type where MEMORY=0, DISK=1, LOCAL_DISK=2; observed function_id 3490366507 for EvictDiskReplica, 1959913856 for the batch variant):Object-loss escalation (verified end to end): after the victim unmounts its memory segment,
victim_dsk_only1holds only its DISK replica (exist=1, tags=['DISK']); one forgedEvictDiskReplica(..., DISK)frame later,exist=0and the replica list is empty — the persistent object is gone from the cluster.Expected secure behavior: erasing another client's replicas requires proving ownership; at minimum the client_id comparison the LOCAL_DISK branch already performs.
Impact
Any network peer that can reach the master RPC port — no credentials, no identity — silently erases the persistence-tier replica metadata of arbitrary keys across all tenants, batch-wipes them, and deletes objects outright once the disk replica is their last copy. In persistence deployments this defeats the durability the tier exists to provide: offloaded KV entries disappear from the cluster's index, cache hit rates collapse, and deleted entries force recomputation. Integrity and availability of stored object metadata; no confidentiality effect. The affected deployment form is the documented persistence configuration (
--root_fs_dir). Suggested CVSS:3.1 vector AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H (9.1), CWE-862. Affected: mooncake-store master <= 0.3.13.post1 (latest release), no patched version yet.Before submitting...
@github-actions[bot] commented on GitHub (Oct 5, 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 6, 2026):
Code-confirmed on current main (
245e7106).MasterService::EvictDiskReplica(mooncake-store/src/master_service.cpp:6368) builds itstarget_predexactly as quoted: the DISK branch matchesr.is_disk_replica()and nothing else, while the LOCAL_DISK branch of the same lambda additionally requires the descriptor's client_id to equal the caller-supplied one (6390-6398). When the erasure leaves the object invalid,accessor.Erase()at 6467 deletes the whole object, andBatchEvictDiskReplica(6482) loops the same path. So the asymmetry the report leans on is real: ownership filtering was considered for this function and applied to exactly one of its two branches.Same root cause as #4474/#4475: client_id is a self-declared request field with nothing binding it to the connection, so copying the LOCAL_DISK filter into the DISK branch would stop accidents, not an attacker who can read victim UUIDs through the same unauthenticated surface. One wrinkle the eventual fix has to answer: persistence-tier replicas can legitimately outlive the client that wrote them (owner gone, object still served from disk), so an ownership rule here needs to decide who may retire an orphaned DISK replica, not just compare UUIDs. Grouping this with the master-RPC identity discussion rather than patching the branch in isolation. Severity and advisory handling are the core team's call, as with the rest of this series.