mcp-auth: check-then-act гонка позволяет конкурентным запросам обойти порог brute-force лимитера /mcp #83

Closed
opened 2026-06-21 02:33:12 +03:00 by Ghost · 0 comments

Найдено в 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 (другой вектор уклонения от того же лимитера)

Найдено в 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 (другой вектор уклонения от того же лимитера)
Ghost closed this issue 2026-06-21 14:10:32 +03:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: vvzvlad/gitmost#83