← back to Ticket System
harden lockout prune: keep active in-window fail-records, prune only expired/stale (code-review W2, session close)
e7768c09527d6728e0e964ad981b94faea8e60b4 · 2026-08-25 14:45:22 -0700 · Steve
Files touched
Diff
commit e7768c09527d6728e0e964ad981b94faea8e60b4
Author: Steve <steve@designerwallcoverings.com>
Date: Tue Aug 25 14:45:22 2026 -0700
harden lockout prune: keep active in-window fail-records, prune only expired/stale (code-review W2, session close)
---
server.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/server.js b/server.js
index a6c5ae9a..c4544e46 100644
--- a/server.js
+++ b/server.js
@@ -91,7 +91,9 @@ function noteAuth(req, ok) {
rec.count++;
if (rec.count >= FAIL_MAX) rec.until = now + LOCK_MS;
authFails.set(ip, rec);
- if (authFails.size > 5000) for (const [k, v] of authFails) if (!v.until || now > v.until) authFails.delete(k); // prune
+ // prune only truly-inactive records: expired locks OR window-stale (count would reset anyway).
+ // NOT active in-window records (until==0, count<MAX) — deleting those resets a live attacker's count.
+ if (authFails.size > 5000) for (const [k, v] of authFails) if ((v.until && now > v.until) || (now - v.first) > FAIL_WINDOW_MS) authFails.delete(k);
}
// Claude-spawning endpoints (/api/run, /api/dtd) must run from a LOCAL operator only.
// Over the public `tickets` tunnel these would let a remote actor (past the shared cred)
← 4f405809 Loopback-gate /api/run + /api/dtd: block Claude-spawning end
·
back to Ticket System
·
auto-data-snapshot: 2026-08-25T18:53:12 (1 data files) — tmp aa4e0d5c →