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
I maintainer di solito rispondono entro 1 giorno
@Ranjeet2063 ci sta già lavorando.
Dal 20/9/2026.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 42/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- typescript
- Ambito
- authorization, backend
Direzione di ricerca
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.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
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."
- Lingua principale
- TypeScript
- Stelle
- 2
- Fork
- 90
- Merge medio
- 31m
- PR unite (30g)
- 20
Preparare l'ambiente
- Include un Dockerfile o un file Docker Compose
- Nessun modello di pull request
- Nessuna guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di MergeFi/backend
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
I maintainer di solito rispondono entro 1 giorno
-
bug security
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno
-
bug testing
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
I maintainer di solito rispondono entro 1 giorno
-
bug security
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di MergeFi/backend
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
zapcooking/frontend#946 ·
I maintainer di solito rispondono entro 1 giorno
-
enhancement good first issue
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
WiliamRosa/cosmos-semantic-platform#40 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 77/100
liberation-data/drivine#733 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 64/100
makecindy/cindy#10062 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno