CreateTeamDto.createdById is taken from the request body, so a caller can create a team owned by someone else
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 75/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- typescript
Línea de trabajo
Start with TeamsService.create in src/teams/teams.service.ts, then read CreateTeamDto and the controller in the paths named in the issue. Check the existing team service specs and how member IDs are validated. Done means a request cannot choose an arbitrary team owner, and a service spec covers a body-supplied createdById that differs from the caller.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Location — src/teams/teams.service.ts:38-43 (TeamsService.create), DTO field src/teams/dto/create-team.dto.ts:49-52 (CreateTeamDto.createdById), controller src/teams/teams.controller.ts:43.
Problem — The authenticated caller's id is used only as a fallback for a client-supplied value:
const team = await this.teamRepo.save(
this.teamRepo.create({
name: dto.name?.trim() ?? dto.name,
// Fall back to the authenticated caller's id when the client omits createdById.
createdById: dto.createdById ?? callerUserId,
}),
);
CreateTeamDto.createdById is validated as @IsOptional() @IsUUID() and nothing else. There is no check that it equals user.userId from @CurrentUser(), and no check that the referenced user even exists (the existence loop above only validates members[].userId, not createdById). So any caller holding SPONSOR or MAINTAINER can set createdById to an arbitrary UUID.
Why it matters — Team.createdById is the only ownership field on the entity. Issue #357's fix made it the fallback owner precisely so a team cannot be created with no owner, and it is the field any ownership check on PATCH /teams/:id/splits or POST /teams/:id/assign/:bountyId must key on. Letting the client choose it means:
- The audit trail is wrong: a team whose splits pay out real money is attributed to a user who never created it, and the real creator leaves no record anywhere.
- It pre-breaks the ownership checks this field exists to support. Once a check of the form
team.createdById === callerIdis added, a caller can still hand ownership to an account they control, or — in the other direction — plant a team attributed to a victim so the victim appears responsible for its payout terms. - Passing an unknown UUID is also accepted; because
Team.createdByisonDelete: 'SET NULL'/nullable: true, there is no FK rejection path that reliably catches it at insert time for an id that does not exist, so the team can end up with a dangling owner id (the condition #357 set out to prevent).
Reproduction / failure path
- Authenticate as user A (SPONSOR). Note A's id.
POST /teamswith body{"name":"t","createdById":"<user B's uuid>","members":[{"userId":"<A>","percentage":100}]}.- Returns 201 with
createdByIdset to B. Nothing links the team to A. - Repeat with a random UUID that belongs to no user — also accepted.
Suggested fix
- Remove
createdByIdfromCreateTeamDtoentirely and setcreatedById: callerUserIdunconditionally in the service. The caller id is already available and is the only trustworthy source. - If an admin-on-behalf-of flow is genuinely needed, keep the field but accept it only when the caller holds
UserRole.MAINTAINER, and validate the referenced user exists with the same batched existence check used for members; otherwise reject withForbiddenException. - Add a service spec asserting that a body-supplied
createdByIddifferent from the caller's id does not end up on the saved entity.
- Lenguaje dominante
- TypeScript
- Estrellas
- 2
- Forks
- 90
- Merge medio
- 31 min
- PR fusionados (30 d)
- 20
Preparar el entorno
- Incluye un Dockerfile o un archivo de Docker Compose
- Sin plantilla de pull request
- Sin guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de MergeFi/backend
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
Los mantenedores suelen responder en 1 día
-
bug security
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
Los mantenedores suelen responder en 1 día
-
bug testing
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
Los mantenedores suelen responder en 1 día
-
bug security
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Los mantenedores suelen responder en 1 día
Todos los issues de MergeFi/backend
Issues similares
-
ログイン中の404画面にヘッダーとナビを出すAbiertoCodex使用可 コード
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
ryuki-moro/Nicomaru#218 ·
Los mantenedores suelen responder en 3 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
sveltejs/svelte-eslint-parser#1008 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
silverbucket/inbox-rs#351 ·
Los mantenedores suelen responder en 1 día
-
[Bug]: The H2 series' and the H3C's fan 3 is labelled "Chamber Fan", Bambu calls it the exhaust fanAbiertoarea:ui
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
Los mantenedores suelen responder en 1 día
-
bug front P2
Dificultad 2/5 1-3 horas Aptitud para principiantes 86/100
invoicerr-app/invoicerr#964 ·
Los mantenedores suelen responder en 1 día