Skip to content

Tell RPC handlers whether a request arrived encrypted - #1186

Open
pblazej wants to merge 1 commit into
mainfrom
triage/clt3536-e2ee-data-recv-v2
Open

pblazej wants to merge 1 commit into
mainfrom
triage/clt3536-e2ee-data-recv-v2

Conversation

@pblazej

@pblazej pblazej commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

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

RpcInvocationData has a new encryptionType property. 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

Behavior Swift (this PR) JS Rust Android
Unencrypted packet from a participant Delivered as .none Delivered as NONE (RTCEngine.ts) Delivered as None (rtc_session.rs) Delivered as NONE (RTCEngine.kt)
Data event has the encryption type Yes Yes (CoreRoom.ts) No (room/mod.rs) Yes (Room.kt)
RPC handler has the encryption type Yes, new No (utils.ts) No (room/mod.rs) No (Room.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

@pblazej
pblazej marked this pull request as ready for review October 30, 2026 12:06

@devin-ai-integration devin-ai-integration Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Newer findings are available below. Devin Review posted a newer report on this PR, in addition to the findings presented here.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

@pblazej
pblazej marked this pull request as draft October 30, 2026 12:39
@pblazej
pblazej marked this pull request as ready for review October 30, 2026 13:20

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Devin Review

Comment on lines +270 to +272
return packet.participantSid.isEmpty
&& packet.participantIdentity.isEmpty
&& user.participantIdentity.isEmpty

@devin-ai-integration devin-ai-integration Bot Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟥 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.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@pblazej
pblazej marked this pull request as draft November 3, 2026 09:21
@pblazej pblazej changed the title Drop and report unencrypted data packets when data channel encryption is on Tell RPC handlers whether a request arrived encrypted Nov 3, 2026
@pblazej
pblazej marked this pull request as ready for review November 3, 2026 09:59
@pblazej
pblazej marked this pull request as draft November 3, 2026 10:11
@pblazej
pblazej force-pushed the triage/clt3536-e2ee-data-recv-v2 branch from 1c58d6c to abc833e Compare November 3, 2026 10:13
@pblazej
pblazej marked this pull request as ready for review November 3, 2026 10:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant