-
-
Notifications
You must be signed in to change notification settings - Fork 146
Description
Summary
The webhook and invitation repositories have findOneById(), deleteOneById(), and updateOneById() methods that query by resource ID without space_id filtering, allowing authenticated users to delete/update webhooks and invitations belonging to other spaces.
Details
Webhook IDOR
File: packages/persistence/src/webhook/webhook.repository.ts
findOneById() (line 22-31), deleteOneById() (line 70-72), and updateOneById() (line 58-68) all query by id only without space scoping:
// VULNERABLE - line 22
async findOneById(id: string): Promise<Option<WebhookDo>> {
const wb = await this.txContext
.getCurrentTransaction()
.selectFrom("undb_webhook")
.selectAll()
.where((eb) => eb.eb("id", "=", id)) // NO space_id filter
.executeTakeFirst()
}Compare with the secure find() method (line 37-50):
// SECURE - uses space scoping
.where((eb) => {
const visitor = new WebhookFilterVisitor(eb, this.context.mustGetCurrentSpaceId())
spec.accept(visitor)
return visitor.cond
})Invitation IDOR
File: packages/persistence/src/member/invitation.repository.ts
deleteOneById() (line 19-23) and updateOneById() (line 25-37) query by id only. Compare with insert() and upsert() which correctly use this.context.mustGetCurrentSpaceId().
Command Handlers
delete-webhook.command-handler.ts: Directly callsthis.repository.deleteOneById(command.input.id)without space checkdelete-invitation.command-handler.ts: Directly callsthis.repo.deleteOneById(command.id)without space check
Impact
An authenticated user in Space A can delete/update webhooks and invitations belonging to Space B.
Suggested Fix
Add space_id to the WHERE clause in findOneById(), deleteOneById(), and updateOneById() for both repositories, using this.context.mustGetCurrentSpaceId() consistent with how the find() method already scopes.