Skip to content

Commit 0411333

Browse files
committed
fix(facility): patch TOCTOU vulnerability in assignment repository
1 parent 2c22d9b commit 0411333

2 files changed

Lines changed: 24 additions & 4 deletions

File tree

src/modules/event/facility-assignments/repository.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,30 @@ export const insertFacilityAssignment = dbAction(
1818
})
1919
.from(schema.facility)
2020
.where(and(eq(schema.facility.id, data.facilityId), isNull(schema.facility.deletedAt)))
21-
.limit(1);
21+
.limit(1)
22+
.for("update");
2223

2324
if (facilityInfo == null) return;
2425

26+
const [duplicate] = await tx
27+
.select({ id: schema.eventFacility.id })
28+
.from(schema.eventFacility)
29+
.where(
30+
and(
31+
eq(schema.eventFacility.eventId, eventId),
32+
eq(schema.eventFacility.facilityId, data.facilityId),
33+
data.venueAllotmentId != null
34+
? eq(schema.eventFacility.venueAllotmentId, data.venueAllotmentId)
35+
: isNull(schema.eventFacility.venueAllotmentId),
36+
isNull(schema.eventFacility.deletedAt),
37+
),
38+
)
39+
.limit(1);
40+
41+
if (duplicate != null) {
42+
return { success: false as const, conflict: { event: { id: eventId } } };
43+
}
44+
2545
if (facilityInfo.overlapPolicy === "exclusive") {
2646
const [overlap] = await tx
2747
.select({
@@ -45,7 +65,7 @@ export const insertFacilityAssignment = dbAction(
4565
if (overlap != null) return { success: false as const, conflict: overlap };
4666
}
4767

48-
const [assignment] = await db
68+
const [assignment] = await tx
4969
.insert(schema.eventFacility)
5070
.values({
5171
eventId: eventId,

test/integration/facility.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ describe("Facility Integration Tests", () => {
362362
).rejects.toThrow("The facility is already assigned to the event");
363363
});
364364

365-
test("TOCTOU duplicate checker fails atomically under concurrent assignments", async () => {
365+
test("TOCTOU duplicate checker natively blocks duplicates under concurrent assignments", async () => {
366366
const { event, admin } = await createOrganizerTestSetup();
367367
const facility = await createFacility({
368368
name: `RaceAssoc-${nanoid()}`,
@@ -385,7 +385,7 @@ describe("Facility Integration Tests", () => {
385385
),
386386
});
387387

388-
expect(allAssignments.length).toBeGreaterThan(1);
388+
expect(allAssignments.length).toBe(1);
389389
});
390390

391391
test("rejects assignment if venueAllotmentId exists but belongs to a totally different event", async () => {

0 commit comments

Comments
 (0)