Skip to content

Build1 publisher2 min readPublished

Asserting a minimum response time catches a login that stopped hashing passwords

Rust check runner probatum added a min_ms floor in v0.12.0 that fails a login check when its 336 ms Argon2 verification is swapped for a string compare. The floor holds only if it is set from a measured baseline, with room between the healthy path and the broken one.

The Engineer · Build desk

Illustration accompanying Asserting a minimum response time catches a login that stopped hashing passwords

What happened

  • Swapping the hash for a string comparison returns the same 401 and body, so every functional check stays green while the endpoint gets about 100 times faster.
  • The max_ms ceiling has failed too-slow responses since v0.5.0; issue #8, opened August 15th, asked for the matching floor.
  • Timing the request through probatum's run escape hatch failed: the 0.9.0 image has no curl, and its BusyBox date ignores %N and prints whole seconds.
  • Earlier issues such as the cookie jar and extra HTTP verbs shipped the same day; #8 waited five weeks with no commits, then four releases landed in three days.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • capability A probatum suite can now fail the build when a login stops paying for its hash, a regression that otherwise surfaces only to someone reading latency.
  • decision The floor is coupled to the hash settings: lowering Argon2 cost or moving to faster hardware means re-measuring and moving min_ms in the same change.
  • cost Getting min_ms means upgrading past v0.11.0, and its JSON schema jump from version 2 to 4 makes consumers handle a new Excluded status and null values.

The floor in the author's sketch was 20 ms, on a POST to /auth/login with a wrong password and an expected 401 [13]. Against the 336 ms the author measured [3], that sits about 17 times below the healthy path [2]. Two orders of magnitude faster than 336 ms is about 3.4 ms [1]. A string compare would land roughly 6 times under the floor [2]. Those ratios come from a single measurement on one app. They transfer only if your wrong-password path stays well above the floor on your fastest runner and the broken path stays well below it on your slowest.

The README argues that a floor is sturdier than a ceiling, because noise makes a measurement slower and almost never faster [11]. That holds for false alarms. A loaded runner will not make a 336 ms Argon2 check look like 3 ms. The same asymmetry works against detection. At these numbers, about 17 ms of added delay lifts a string compare over a 20 ms floor [5]. A floor also checks only that the path is slow; any other delay on the same path would satisfy it as well as the hash does.

Whole-second timestamps could never have told the two cases apart, since 336 ms and 3.4 ms both fall inside one second [4]. The author called the minimal image the right call and moved the feature into the config language instead [17]. "It had to be a keyword," the author wrote [7].

v0.12.0 gets the failure semantics right. A response under min_ms exits 1 and reports the measured time as evidence, while exit 2 stays reserved for "couldn't observe" [9]. "A login answering in 2 ms is wrong, not unavailable," the author wrote [10]. Declaring min_ms above max_ms is a config error [12], so nobody can commit a check that no response could satisfy.

The v0.13.1 fix is the same class of bug, found inside the runner. Since v0.6.0, captured output had been capped in memory, and the contains and absent rules ran against that capped copy [15]. Past the bound, a contains could fail on output that held the pattern, and an absent could pass over a FATAL [15]. v0.13.1 evaluates the rules line by line as output arrives and keeps the bounded copy for diagnosis only [15]. "The cap limits what you keep as evidence, never what you check," the author wrote [16]. Two dogfooding checks now cover both directions [15].

What to watch

  • Whether probatum documents a way to derive min_ms from a baseline measured on the runner that executes the suite.
  • Reports of a broken or cached login path clearing a 20 ms floor on loaded CI runners, the false-pass case the README's noise argument leaves open.
  • Whether other check runners that already enforce timeout ceilings add a matching minimum-latency assertion.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories