trackslash
VAULT-93 P2

Right App Lock Password doesn't reset the wait after wrong ones

0
All issues

Description

Bug

  1. Enter the App Lock Password wrong until the lock screen makes you wait.
  2. Wait, then enter it right. The vault opens.
  3. Lock, then enter it wrong once.

Expected: the right password resets the waits, so one wrong attempt after it has no wait, as it did before the first lockout.

Actual: the wait picks up where it left off and keeps growing, as if the right password had never been entered.

Cause

This is on purpose, from #681 (security review, VAULT-82). The waits follow AppLockPasswordAttemptCounter's recent count. A right password takes only itself back off that count, and the count goes down by one an hour. Only the in a row count, which decides erase-after-10, starts again. See noteRightAttempt(), G19 in docs/security-model.md, and "Recent" in docs/on-device-encryption.md.

#681 did this because the counter can't tell the real password from a duress one (MANIFESTO C2).

Decision (Bradley, 2026-09-28): any right password resets the waits

Any password that opens a vault, a duress one included, clears the waits as well as the count in a row. This is how things worked before #681. It treats every vault the same, so C2 still holds.

Accepted trade-off: someone who knows a duress password can make 4 guesses at the real one with no wait, open the duress vault, and repeat. Neither the waits nor erase-after-10 limit their guessing on the device then, only the key derivation (about half a second a guess). G19 has to say so plainly.

Rejected: resetting at most once an hour (it kept a limit of about 4–6 guesses an hour for a duress-password holder). Resetting only for the real password isn't possible under C2.

Implementation notes

  • With this, the recent count only ever sits at or below the count in a row, so the waits just follow the count in a row. Remove the recent count (recentWrong, recentWrongAt, recentWrongInterval, the hourly decay) rather than keeping it dead. Old keychain records that still have those fields must keep decoding.
  • resetCountInARow() exists only to keep the waits when the password is turned back on. Turning it off already needs a vault opened, which resets the waits now, so fold it into one reset (or drop it), and update the "Turning it back on" paragraph in the design doc.
  • A restart still restarts a delay in full (AppLockClock going back). Keep that.

Done when

  • AppLockPasswordAttemptCounter resets the waits on any right password, and treats every vault the same (C2).
  • Tests are updated or replaced, including countAttempt_wrongAttemptsEitherSideOfARightOne_keepEscalatingTheDelay, recentWrong_goesDownByOneAnHour, unlock_wrongPasswordsInterleavedWithADuressPassword_stillEscalate, unlock_withAnyVaultsPassword_clearsTheCountInARowAndKeepsTheRecentCount, and the recentWrong checks in VaultPasswordChangeServiceTests. Add one that shows a wrong attempt right after a right one has no wait.
  • G19 in docs/security-model.md, the design doc's counter section, and the FAQ and App Lock Password screen wording state the new limit.

GitHub

0

No branches or pull requests linked.

Comments

1
Bradley

Fixed in https://github.com/badbundle/vault-app/pull/705 (merged as c9d56c69), as decided above: any password that opens a vault, a duress one included, now resets the waits along with the count towards erasing after 10.

  • AppLockPasswordAttemptCounter keeps one count again, of attempts in a row. The recent count (recentWrong, recentWrongAt, the hourly decay) is removed. A keychain record that still has those fields decodes, and reads as its attempts in a row.
  • A right password calls reset(), which removes the record, so the next attempt has no wait. noteRightAttempt() and resetCountInARow() are gone. Turning the password back on resets the counter too, and the "Turning it back on" paragraph says why that clears nothing new.
  • The accepted limit is stated in G19 and a new "Accepted limits" entry in docs/security-model.md, in the design doc's counter section and consequence 11, and in the Duress Password FAQ: someone with a duress password can make 4 wrong guesses, open the duress vault, and repeat, held back only by the key derivation. G21 and G26 were reworded to match. The on-screen wording is unchanged: "The right password starts the count again" now covers the waits too.
  • Tests: new reset_theNextWrongAttemptDoesntWait (a wrong attempt right after a right one has no wait), countAttempt_rightAttemptsBetweenWrongOnes_neverWaitOrReachTheEraseThreshold, recordWithARecentCount_readsAsItsAttemptsInARow and unlock_wrongPasswordsEitherSideOfADuressPassword_startTheWaitsAgain. The recent-count tests listed in this ticket are replaced. make validate passed.