GHSA-89vx-jh4q-vg3w: High severity npm/@deepstream/server vulnerability
Summary
The RECORDACTION.PATCHMULTI action is not registered in the Valve permission system's RULESMAP (src/services/permission/valve/rules-map.ts). When ConfigPermission.canPerformAction() is called for a PATCHMULTI message, getRulesForMessage() returns null because the action is missing from the map. This triggers an unconditional allow (callback(..., null, true)), completely bypassing all configured Valve permission rules.
Any authenticated user — regardless of their configured permissions — can write arbitrary data to any record using the PATCHMULTI action.
Root Cause
In src/services/permission/valve/rules-map.ts lines 38-54, the RULESMAP[TOPIC.RECORD].actions dictionary maps record actions to permission rule types. The actions registered include: SUBSCRIBE, SUBSCRIBEANDHEAD, SUBSCRIBEANDREAD, READ, HEAD, LISTEN, CREATE, UPDATE, PATCH, NOTIFY, DELETE, ERASE. However, RECORDACTION.PATCHMULTI is absent from this map.
When getRulesForMessage() at line 86-99 encounters an action not in the map, it returns null. In config-permission.ts at line 88-93, when ruleSpecification === null, the callback is invoked with true (allow) unconditionally.
Attack Chain
1. Attacker authenticates with any valid credentials (even a minimal-privilege user) 2. Attacker sends a WebSocket message: {topic: RECORD, action: PATCHMULTI, name: "admin/secret-record", parsedData: [{path: "role", data: "admin"}]} 3. message-processor.ts:68 invokes permission check 4. config-permission.ts:89 → getRulesForMessage() returns null for PATCHMULTI 5. config-permission.ts:92 → unconditional ALLOW 6. Record transition applies the operations — arbitrary record is modified
Impact
- Complete Valve permission bypass for record writes — all configured permission rules are irrelevant - Any authenticated user can overwrite any record, including admin-only records - Mass record overwrites can destroy application state, corrupt sessions, cause service outage - Only exploitable when permission.type is set to config (Valve) — the recommended production configuration per deepstream documentation - Default permission type none (OpenPermission) allows everything already, so default deployments are unaffected
<details><summary>Proof of Concept</summary>
javascript // Connect as a minimal-privilege user const { DeepstreamClient } = require('@deepstream/client'); const client = new DeepstreamClient('localhost:6020'); await client.login({ username: 'restricted-user', password: 'password' });
// This should be blocked by Valve permissions but isn't: // Send raw PATCHMULTI message to bypass all permission rules const connection = client.getConnection(); connection.sendMessage({ topic: 0x52, // TOPIC.RECORD action: 0x50, // RECORDACTION.PATCHMULTI (check actual enum value) name: 'admin/protected-record', parsedData: [ { path: 'permissions', data: 'admin' }, { path: 'secret', data: 'overwritten' } ] }); </details>
Suggested Fix
Add PATCHMULTI to the RULESMAP in src/services/permission/valve/rules-map.ts:
typescript [RECORDACTION.PATCHMULTI]: RULETYPES.WRITE,
This maps PATCHMULTI operations to the same WRITE permission rule that governs UPDATE and PATCH.
Affected Versions
All versions that include PATCHMULTI support with the Valve (ConfigPermission) permission system. The PATCHMULTI action was added in commit 82ffa8119d8f4a8242ac5c3507469a22de746b65 but was never registered in RULESMAP.
Credit
Vulnerability discovered by Zhixi "Jace" Sun of ASM/VI at TikTok.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
npm/@deepstream/serverto a version that resolves this vulnerability.Fixed in 10.1.1 - Configuration
Register the PATCH_MULTI record action in src/services/permission/valve/rules-map.ts and map it to the WRITE permission rule so Valve permissions are enforced.
Deepstream Valve (ConfigPermission) permission system RULES_MAP[TOPIC.RECORD].actions[RECORD_ACTION.PATCH_MULTI] = RULE_TYPES.WRITE
Event History
Frequently Asked Questions
Who can exploit this issue?
Any authenticated user can exploit it, regardless of the Valve permissions configured for that user. Exploitation does not require user interaction.
What access does an attacker gain through the bypass?
An attacker can use the PATCH_MULTI action to write arbitrary data to any record. This bypasses all configured Valve permission rules for that action.
How does the permission check fail?
PATCH_MULTI is absent from the record action rules map. The resulting null rule specification is handled as an unconditional allow by ConfigPermission.canPerformAction().