Skip to content

[Bug] Race condition in card creation — concurrent requests can create multiple default cards #333

@Midoriya-w

Description

@Midoriya-w

Summary

In apps/backend/src/routes/cards.ts, the POST /api/cards endpoint checks if the user has zero cards to decide whether the new card should be the default:

const cardCount = await app.prisma.card.count({ where: { userId } });

const card = await app.prisma.card.create({
  data: {
    isDefault: cardCount === 0,
    ...
  }
});

These are two separate database operations with no transaction or lock between them. If two requests arrive simultaneously when a user has zero cards, both will read cardCount === 0 and both will create a card with isDefault: true — leaving the user with two default cards.

Location

apps/backend/src/routes/cards.tsPOST / handler

Steps to Reproduce

  1. Send two simultaneous POST /api/cards requests for a new user with no existing cards
  2. Both requests read cardCount === 0
  3. Both cards are created with isDefault: true
  4. User now has two default cards data integrity violation

Fix

Wrap the count check and card creation in a single Prisma transaction to prevent the race window.

Impact

Data integrity violation user ends up with multiple default cards causing undefined behaviour in the UI.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions