Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions packages/federation-sdk/src/services/event.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ export class EventService {
Array.from(eventsByRoomId.entries()).map(async ([roomId, events]) => {
for await (const event of events) {
try {
await this.validateEvent(origin, event);
await this.validateEvent(event);
} catch (err) {
this.logger.error({
msg: 'Event validation failed',
Expand Down Expand Up @@ -221,12 +221,25 @@ export class EventService {
);
}

private async validateEvent(origin: string, event: Pdu): Promise<void> {
private async validateEvent(event: Pdu): Promise<void> {
const roomVersion = await this.getRoomVersion(event);
if (!roomVersion) {
throw new Error('M_UNKNOWN_ROOM_VERSION');
}

if (
event.type === 'm.room.member' &&
event.content.membership === 'invite' &&
'third_party_invite' in event.content
) {
throw new Error('Third party invites are not supported');
}

const origin = event.sender.split(':').pop();
if (!origin) {
throw new Error('Event sender is missing domain');
}

Comment on lines +238 to +242
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Bug: Incorrect server name extraction from sender (breaks signature verification, esp. with ports).

Using split(':').pop() returns only the last segment. For MXIDs like @alice:example.org:8448 this yields "8448", which is wrong and will cause signature lookups to fail or be bypassed incorrectly.

Use a single, canonical extractor that returns everything after the first colon. Prefer reusing one helper across the codebase.

Apply this diff:

-    const origin = event.sender.split(':').pop();
-    if (!origin) {
-      throw new Error('Event sender is missing domain');
-    }
+    const origin = this.extractServerNameFromUserId(event.sender);
+    if (!origin) {
+      throw new Error('Event sender is missing domain');
+    }

Add this helper to the class (or adapt your existing extractDomain to keep the port):

// Helper: returns everything after the first ":" in the MXID, preserving optional ":port"
private extractServerNameFromUserId(userId: string): string {
  const idx = userId.indexOf(':');
  return idx > 0 ? userId.slice(idx + 1) : '';
}

Note: event-wrapper.ts uses an extractDomain helper; align both to avoid inconsistencies and ensure ports are preserved for signature keys. Based on relevant code in event-wrapper.ts.

🤖 Prompt for AI Agents
In packages/federation-sdk/src/services/event.service.ts around lines 238 to
242, the current origin extraction using event.sender.split(':').pop()
incorrectly returns only the last segment (breaking MXIDs with ports); replace
this with a helper that returns everything after the first ":" (or adapt the
existing extractDomain to preserve ":port") and use that helper here so e.g.
"@alice:example.org:8448" yields "example.org:8448"; add the helper to the class
(or update the shared extractDomain) and change the code to call it instead of
split(':').pop() to ensure correct server name extraction for signature lookups.

const eventSchema = this.getEventSchema(roomVersion, event.type);

const validationResult = eventSchema.safeParse(event);
Expand Down