Repository navigation
Conversation
| return packet.participantSid.isEmpty | ||
| && packet.participantIdentity.isEmpty | ||
| && user.participantIdentity.isEmpty |
There was a problem hiding this comment.
🟥 Plaintext injection on older servers
On servers that omit participant SIDs, isServerUserPacket accepts a hidden participant's plaintext user packet with empty identities. The receiver delivers unauthenticated data despite enabled data channel encryption.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Valid, but low severity. Since livekit-server v1.9.1, the server sets the outer participant sid on every packet that a participant sends. LiveKit Cloud does this too. Older self-hosted servers have two cases:
- From v1.5.3 to v1.9.0, a hidden participant with permission to publish data can send a packet with this shape.
- Before v1.4.5, any participant can, because this check does not look at the inner
participantSid. Those servers set only that field.
The injected packet can only be a user packet. The app receives it with no participant and with encryptionType .none, the same as data from RoomService.SendData. It cannot reach RPC or stream handlers, and it cannot claim to be another participant. Without this PR, a participant on any server can inject every packet type under any identity.
A follow-up can close both cases: also require an empty inner participantSid, and allow the exception only when server_info.version is 1.9.1 or later. The PR description names v1.9.1 as the minimum server version for this check.
1c58d6c to
abc833e
Compare
Problem
When data channel encryption is on, a participant without the key, or the server, can send an unencrypted data packet. The SDK delivers it and tags it with
encryptionType.none, so an app can check the tag for data and streams. RPC handlers did not get the tag. Thus an app could not tell an unencrypted RPC call from an encrypted one.Change
RpcInvocationDatahas a newencryptionTypeproperty. It tells an RPC handler whether the request arrived encrypted, for RPC v1 and v2 (RPC.swift). With E2EE on, a handler can reject a request with.none.The SDK still delivers unencrypted data, as JS, Rust, and Android do. This change only adds API.
Other SDKs
.noneNONE(RTCEngine.ts)None(rtc_session.rs)NONE(RTCEngine.kt)The RPC row adds information. It does not change which calls run. The same property can go into the other SDKs (CLT-3531 for Rust).
Resolves CLT-3536
Related to CLT-3531