- Ya
- 5 Septemba 2026, 00:04 UTC
- Mwandishi
- Kamo
- Ahadi ya
- 6609aa9
A wrong password now costs something, and the cost climbs. Counted since the subject's last successful sign-in: the first five failures are free, the sixth and every one after it waits five seconds, and the tenth, twentieth and thirtieth hold the door for five, fifteen and thirty minutes. The fortieth puts the address on the organization's permanent blocklist and mails sysadmin. WHO is counted is the part worth reading. The subject is normally the (address, identifier) PAIR, not either half alone. Counting the identifier alone would let anybody who knows a username lock its owner out from the other side of the world; counting the address alone would let one person behind a shared office NAT lock out their colleagues. A pair-only ladder has one hole, though — spray one password across two hundred usernames and no single pair ever reaches six — so an address seen failing against more than ten DISTINCT identifiers becomes a subject in its own right, and from then on every failure from it counts on one ladder whatever account it names. The harsher of the two governs. Checked BEFORE the password is compared, at every credential-bearing terminus: both sign-in paths and the MFA challenge, whose six-digit space gets its own ladder so a fumbled authenticator cannot spend the password step's budget. A caller who can still measure the difference between a right and a wrong password while locked out has a working oracle and a lockout that only wastes their time. Failures are counted for identifiers that name nobody, exactly as for ones that do. Counting only real accounts would make a wrong username cheap and a right one expensive, which is an account-enumeration oracle built out of latency. Redis-backed, 30-day sliding TTL, cleared where lastLoginService already stamps a real sign-in. Fail-open on every Redis error, matching AccessDecisionService's doctrine: a lockout that fails closed on an infrastructure wobble locks every tenant out of their own platform. Failures are logged WITH the throwable, not just its message — a defect in this path is otherwise indistinguishable from an outage, and would silently switch the whole control off. The fortieth failure blocks the address by itself rather than relying on the caller to go on and write the blocklist row. That row sits behind a 30-second verdict cache, and on a host naming no organization there is no row to write at all; a control that depends on its caller to be effective is one a later refactor switches off by accident. PROGRESSIVE_LOGIN_LOCKOUT appears in Detection Rules as a rule that cannot be switched off or deleted, and whose thresholds are not tenant data — an editable threshold is an off switch wearing a different hat. Recipients stay editable, or the block notice could only ever reach the platform operator. The lock lives in the service, not the controller: a gate that can be reached around is not a gate. The row is materialised on READ, because every existing organization already holds the five original rules and would never reach the seed-on-empty branch.