payload.secret != expected_secret short-circuits on the first differing byte, which leaks timing information about how many leading bytes of a guess are correct. Use subtle::ConstantTimeEq instead.