mcp-auth: check-then-act гонка позволяет конкурентным запросам обойти порог brute-force лимитера /mcp #83
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Найдено в multi-aspect code review всех изменений с коммита
053a9c0d(ветка develop).Грань: stability / security · Severity: warning
Где:
apps/server/src/integrations/mcp/mcp-auth.helpers.ts:403-480Проблема
isBlocked проверяется синхронно (L403-411), а recordFailure вызывается на L470-473 — после await findWorkspace, await enforceBasicGate и bcrypt-несущего login/verifyCredentials. На каждом await event loop уступает, поэтому пачка из N конкурентных Basic-запросов на один email видит count=0 на гейте, все прогоняют bcrypt, все падают и лишь затем все зовут recordFailure. /mcp принимает неаутентифицированные POST, поэтому слать конкурентные запросы тривиально — атакующий получает существенно больше threshold (5) попыток за окно 60с. Глобальный per-email ключ подвержен той же гонке. По формулировке кода это «speed bump, не жёсткая граница» → warning.
Предлагаемый фикс
Сделать проверку-и-инкремент атомарными относительно async-работы: оптимистично recordFailure (или счётчик in-flight попыток) ДО await login/verifyCredentials, reset/декремент на успехе; синхронный isBlocked должен учитывать попытки в полёте, а не только завершённые.
Связанные: #70 (другой вектор уклонения от того же лимитера)