Description
The createSession function in lib/sessionManager.js (lines 16-22) has a classic Time-of-Check-Time-of-Use (TOCTOU) race condition. It reads existing sessions, deletes them, then creates a new one — but these three steps are not atomic.
const existingSessions = await redis.smembers(`user:sessions:${userId}`);
if (existingSessions && existingSessions.length > 0) {
const pipeline = redis.multi();
existingSessions.forEach((sid) => pipeline.del(`session:${sid}`));
pipeline.del(`user:sessions:${userId}`);
await pipeline.exec();
}
Impact
If two login requests arrive concurrently for the same user:
- Request A reads
user:sessions:{userId} — empty (1 session)
- Request B reads
user:sessions:{userId} — empty (the same 1 session)
- Both A and B create new sessions and add themselves to the set
- Both logins succeed, violating the "single session" policy
A user can have multiple active sessions simultaneously, defeating the concurrent-login prevention mechanism.
File
lib/sessionManager.js:16-22 — createSession function
Suggested Fix
Use a distributed lock (e.g., via the existing lockManager.js) around the read-then-delete-then-create sequence, or use a Redis Lua script that atomically clears old sessions and creates the new one in a single operation.
Description
The
createSessionfunction inlib/sessionManager.js(lines 16-22) has a classic Time-of-Check-Time-of-Use (TOCTOU) race condition. It reads existing sessions, deletes them, then creates a new one — but these three steps are not atomic.Impact
If two login requests arrive concurrently for the same user:
user:sessions:{userId}— empty (1 session)user:sessions:{userId}— empty (the same 1 session)A user can have multiple active sessions simultaneously, defeating the concurrent-login prevention mechanism.
File
lib/sessionManager.js:16-22—createSessionfunctionSuggested Fix
Use a distributed lock (e.g., via the existing
lockManager.js) around the read-then-delete-then-create sequence, or use a Redis Lua script that atomically clears old sessions and creates the new one in a single operation.