From 300d33156204a369214e1876fc80d43578710ba0 Mon Sep 17 00:00:00 2001 From: ScreenTinker Date: Fri, 12 Jun 2026 10:38:32 -0500 Subject: [PATCH] fix(security): rate-limit the whole /api/provision pairing surface (#88) POST /api/provision (the routes/provisioning.js router endpoint) pairs a device by pairing_code with no rate limit - the limit at server.js:287 was bound only to the /api/provision/pair override. An authenticated user could brute-force 6-digit pairing codes against the bare endpoint to claim devices in the unclaimed pool. Bind the rate limit to the /api/provision mount so it covers both pairing paths. Verified: 6 rapid POSTs to /api/provision now 429 on the 6th (was unlimited); /api/provision/pair still 429s on the 6th. Closes #88 Co-Authored-By: Claude Opus 4.8 (1M context) --- server/server.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/server/server.js b/server/server.js index c9cbd12..e953aa0 100644 --- a/server/server.js +++ b/server/server.js @@ -283,8 +283,12 @@ app.use('/api/auth/register', rateLimit(60000, 5)); // 5 registrations per minut // path prefix first, so this fires before /api/auth catches the request. app.use('/api/auth/users', rateLimit(60000, 20)); app.use('/api/auth', require('./routes/auth')); -// Rate limit pairing to prevent brute force (5 attempts per minute per IP) -app.use('/api/provision/pair', rateLimit(60000, 5)); +// Rate limit pairing to prevent brute force (5 attempts per minute per IP). +// #88: bind this to the whole /api/provision surface, not just /pair - the bare +// POST /api/provision (routes/provisioning.js) is a second pairing endpoint that +// was unthrottled, letting an authed user brute-force pairing codes. /api/provision +// matches both /api/provision and /api/provision/pair. +app.use('/api/provision', rateLimit(60000, 5)); // Rate limit expensive operations app.use('/api/status/export', rateLimit(60000, 5)); // 5 exports per minute app.use('/api/status/import', rateLimit(60000, 3)); // 3 imports per minute