EscrowService.refund()/release() check the caller's role but never bind the check to the specific escrow's sponsor — any SPONSOR can force-refund any other sponsor's escrow

Đang mở
#299 2 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

@Ranjeet2063 đang làm issue này rồi.

Từ ngày 20/9/2026.

Đánh giá

Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
42/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
typescript
Lĩnh vực
authorization, backend

Hướng nghiên cứu

Start in src/escrow/escrow.service.ts at refund() and release(), which take only escrowId, then in src/escrow/escrow.controller.ts where the route is gated by RolesGuard in src/auth/guards/roles.guard.ts. Thread the caller's id and role from the controller into the service and compare it against escrow.sponsorId for sponsors. Done when a sponsor who did not fund an escrow gets a rejection on refund and release, and the funder's own calls still succeed. The maintainer-of-repository check is not specified, so confirm its scope with the maintainers first.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

EscrowController.refund() (src/escrow/escrow.controller.ts) is gated by @Roles(UserRole.MAINTAINER, UserRole.SPONSOR) via RolesGuard. Reading src/auth/guards/roles.guard.ts, RolesGuard.canActivate only checks requiredRoles.some((role) => user.roles.includes(role)) — it has zero concept of which resource is being acted on. It never compares the authenticated caller's id to anything on the target Escrow.

EscrowService.refund(escrowId) (src/escrow/escrow.service.ts) takes only escrowId — no caller identity is threaded through at all — and unconditionally refunds to escrow.fundedByAddress, the original funder. So any authenticated user holding the SPONSOR role (not just the sponsor who actually funded this specific escrow, tracked on escrow.sponsorId) can call POST /escrow/:id/refund for any LOCKED escrow in the system and force it back to REFUNDED — cancelling a rival sponsor's active bounty/milestone escrow, even one where a contributor has already done the work and is waiting on release(). Funds don't go to the attacker (they return to the rightful original funder), so this is a griefing/availability attack rather than theft, but it lets one sponsor account unilaterally kill any other sponsor's in-flight payout.

This is distinct from #40 (DTOs trusting client-supplied recipient/funder ids) and #41 (TeamsService.assignToBounty missing an ownership guard on team assignment) — this is specifically the escrow refund/release authorization path lacking an escrow.sponsorId === callingUser.id (or equivalent maintainer-of-repo) check. Note that right now this is latent rather than actively exploitable, because (per the separate "nothing grants SPONSOR/MAINTAINER role" finding) every user is created with only roles: [UserRole.CONTRIBUTOR] and role assignment is currently unreachable through the app's own API. But the moment that's wired up (or a seed script/admin panel grants roles, which is exactly how local dev and e2e fixtures already assign roles), this gap becomes immediately live.

Fix: in EscrowService.refund/release, accept the authenticated caller's id/role from the controller and assert it matches escrow.sponsorId (for SPONSOR) or an appropriate maintainer-of-repository check (for MAINTAINER), not just "has a SPONSOR/MAINTAINER role somewhere."

Ngôn ngữ chính
TypeScript
Star
2
Fork
90
Merge trung bình
31 phút
Pull request đã merge (30 ngày)
20

Chuẩn bị môi trường

  • Có Dockerfile hoặc tệp Docker Compose
  • Không có mẫu pull request
  • Không có hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của MergeFi/backend

Tất cả issue của MergeFi/backend

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.