Ownership Checks

Roles are Not Enough

Every customer has the customer role, so a roles guard cannot stop Asha from reading Ravi's order GET /orders/ORD-9. This bug is called IDOR (Insecure Direct Object Reference) and is one of the most common API vulnerabilities. Always scope queries to the current user.

src/orders/orders.service.ts

@Injectable()
export class OrdersService {
  constructor(private readonly prisma: PrismaService) {}

  async findOneForUser(orderId: string, user: JwtUser) {
    const order = await this.prisma.order.findFirst({
      where: {
        id: orderId,
        ...(user.roles.includes('admin') ? {} : { userId: user.id }),   // owner filter in the query
      },
      include: { items: true },
    });
    // 404, not 403: do not reveal that the order exists
    if (!order) throw new NotFoundException('Order not found');
    return order;
  }
}

Example

curl -H "Authorization: Bearer <asha-token>" http://localhost:3000/orders/ORD-7781
curl -i -H "Authorization: Bearer <asha-token>" http://localhost:3000/orders/ORD-9

Example output

{"id":"ORD-7781","userId":12,"status":"DELIVERED","total":"2598.00","items":[...]}

HTTP/1.1 404 Not Found
{"message":"Order not found","error":"Not Found","statusCode":404}