Current Behavior
The SSE presentation fanout has no per-user / per-tenant / per-session / per-room audience scoping. The hub registry is keyed only by channel and every payload is sent to every connected client:
// runtime/contracts/sse/sse.go
clients map[chan []byte]bool // lines 21-25 — no user/session/topic key
for client := range hub.clients { // lines 118-125
select { case client <- payload: default: }
}
The fanout interface itself carries no audience parameter, and EventEnvelope has no user/session/audience field:
// runtime/contracts/types.go:148-150
SendPresentationEvents(context.Context, []EventEnvelope) error
// EventEnvelope (lines 53-59): ID, TraceParent, Category, Type, Value -- no audience
Existing mitigations (why this is scoped, not unbounded):
- Event-type scoping: the generated wrapper forwards only events whose
Type is in the bound subscription set + query-invalidation (internal/appgen/source_realtime.go:398-439). This is topic-scoped, not user-scoped.
- Connection-level guards: the
/_gowdk/realtime/events handler runs runGuards and route-matched realtimeStreamGuards before streaming (source_realtime.go:312-387). This gates who may connect, not which events they receive.
So any user-specific presentation payload of a subscribed type is delivered to every authenticated client connected to that stream.
Expected Behavior
There should be a way to scope a presentation event to an audience (user/tenant/session/room) so that applications emitting user-specific payloads don't leak them to other connected clients. E.g. an audience/topic field on EventEnvelope (or a fanout method that takes a target), with the hub filtering delivery accordingly.
Evidence
runtime/contracts/sse/sse.go:21-25,118-125
runtime/contracts/types.go:53-59,148-150
internal/appgen/source_realtime.go:398-439 (type-scoping), :312-387 (connection guards)
Impact
High (security/privacy) for any app that emits user-specific presentation payloads. Currently safe only for globally-public events; the framework offers no primitive to scope otherwise.
Current Behavior
The SSE presentation fanout has no per-user / per-tenant / per-session / per-room audience scoping. The hub registry is keyed only by channel and every payload is sent to every connected client:
The fanout interface itself carries no audience parameter, and
EventEnvelopehas no user/session/audience field:Existing mitigations (why this is scoped, not unbounded):
Typeis in the bound subscription set + query-invalidation (internal/appgen/source_realtime.go:398-439). This is topic-scoped, not user-scoped./_gowdk/realtime/eventshandler runsrunGuardsand route-matchedrealtimeStreamGuardsbefore streaming (source_realtime.go:312-387). This gates who may connect, not which events they receive.So any user-specific presentation payload of a subscribed type is delivered to every authenticated client connected to that stream.
Expected Behavior
There should be a way to scope a presentation event to an audience (user/tenant/session/room) so that applications emitting user-specific payloads don't leak them to other connected clients. E.g. an audience/topic field on
EventEnvelope(or a fanout method that takes a target), with the hub filtering delivery accordingly.Evidence
runtime/contracts/sse/sse.go:21-25,118-125runtime/contracts/types.go:53-59,148-150internal/appgen/source_realtime.go:398-439(type-scoping),:312-387(connection guards)Impact
High (security/privacy) for any app that emits user-specific presentation payloads. Currently safe only for globally-public events; the framework offers no primitive to scope otherwise.