mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #4475] [Bug]: Unauthenticated task assignment, queue theft, and fake completion in Mooncake Store Master #1134
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#1134
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/4475
Bug Report
Summary
The replication/migration task system of Mooncake Store Master is exposed on the unauthenticated RPC port (default 0.0.0.0:50051) without caller validation.
CreateCopyTask/CreateMoveTaskaccept any object key and attacker-chosen target segments and assign the resulting work to the owner of the source segment;FetchTaskshands out task queues based on a self-declared client_id;MarkTaskToCompletecloses a task when the caller claims that same client_id. Together this gives an unauthenticated peer three primitives: force real transfer work onto a victim, steal a victim's task queue, and mark tasks successful without any work. Runtime-confirmed on the master binary shipped in the 0.3.13.post1 wheel (latest release); no fix available. Suggested severity: High, CVSS 8.2.Details
MasterService::CreateCopyTask(key, targets)(mooncake-store/src/master_service.cpp) validates only that each target segment exists and is allocatable. It never checks who ownskey: it looks up the victim object's metadata, picks a source replica, resolves the source segment's owner viaGetClientIdBySegmentName, and submits the task assigned to that owner's client_id.CreateMoveTaskbehaves the same. So any caller decides which object is replicated or moved and into which segments, and the work lands in the victim's queue.The task store (mooncake-store/src/task_manager.cpp) keys everything on a caller-supplied UUID:
pop_tasks(client_id, batch)returns the pending queue of whatever client_id the request names, andcomplete_task(client_id, task_id, ...)succeeds whenevertask.assigned_client == client_idfrom the request. No authentication binds the claimed identity to the connection.QueryTask(task_id)returns the full task record includingassigned_client, so the needed victim client_id comes from the same unauthenticated API.Runtime-verified on 0.3.13.post1 (frames forged over coro_rpc, same transport as the Remove issue): a task created with
CreateCopyTask(victim_key, [attacker_segment])was assigned to the victim's client_id — the returned task payload names the victim's segment as source and the attacker's segment as target;FetchTasksclaiming the victim's client_id handed the task to the attacker;MarkTaskToCompletethen flipped it to SUCCESS two milliseconds after creation, before any copy RPC could occur (the task had also left the victim's pending queue via the theft, so the victim's worker could no longer pick it up).PoC
Environment as for the Remove report: the 0.3.13.post1 wheel's
mooncake_masteron 0.0.0.0:50051, a victim store client with segmentseg_victimholding objectvictim_task_key, and an attacker store client with its own segmentseg_attacker. The attacker forges coro_rpc frames (20-byte header, magic=21; struct_pack bodies captured once by proxying a legit client, then replayed with patched fields; observed function_ids: CreateCopyTask=2013387680, QueryTask=125921908, FetchTasks=3742636100, MarkTaskToComplete=2802188309):Observed: each step returns success; the final QueryTask reports SUCCESS although the task was created two milliseconds earlier and no copy RPC ever ran. The task payload returned by FetchTasks is
{"tenant_id":"default","key":"victim_task_0001","source":"<victim segment>","targets":["<attacker segment>"],...}, confirming both the forced assignment and the attacker-directed target. Expected secure behavior: task creation requires ownership of the key, and fetching/completing requires an authenticated identity matching the assignee.Impact
Any network peer that can reach the master RPC port, without credentials: (1) submits copy/move tasks for arbitrary victims' objects — the victim's client picks them up and performs real data transfers, so an attacker drives other tenants' CPU and network at zero cost, with attacker-chosen targets including the attacker's own segments; (2) claims a victim's queue with the self-declared client_id, stalling the victim's migration and offload; (3) marks tasks successful without work, so replication the system believes happened never did — silent failure of the data-protection goal. Availability and integrity of the replication subsystem are affected; no confidentiality effect was demonstrated in this report. Suggested CVSS:3.1 vector AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H (8.2), 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 5, 2026):
Code-confirmed on current main (
0d1a8040).(Edit: an earlier revision of this comment cited line numbers from my stale local branch; the references below are against main.)
CreateCopyTask(mooncake-store/src/master_service.cpp:13728) validates that each target segment exists and is allocatable, then resolves the source segment's owner throughGetClientIdBySegmentNameand submits the task under that owner's UUID. Who is calling never enters the picture.CreateMoveTaskis the same shape. On the store side,pop_tasksandcomplete_task(mooncake-store/src/task_manager.cpp:58 and :113) key everything on the caller-supplied UUID, withtask.assigned_client != client_idas the only guard, andQueryTaskhanding outassigned_clientcloses the loop you describe: the victim's UUID is available from the same unauthenticated API.This shares the root cause with #4474: nothing on the master RPC plane binds a connection to an identity, so field comparisons inside the request cannot fix queue theft or fake completion. Once identity exists, an ownership check on task creation (caller must own
key) and binding fetch/complete to the authenticated assignee both become meaningful. Grouping this with the master-RPC auth discussion rather than patching the checks in isolation.