Use a constant-time comparison function whenever you check an untrusted value against a secret one: a MAC, a webhook signature, an API token or a password reset code. An ordinary equals check can stop at the first differing byte, and that timing difference can leak information to a patient attacker.
What goes wrong with a plain equals
Most string comparison routines return as soon as they find a mismatch. If the first byte is wrong, the check ends quickly. If the first ten bytes are right, it takes slightly longer.
An attacker who can send many guesses and measure response times can, in theory, learn the value one byte at a time. Over a noisy network this is hard, but it gets easier from inside the same data center or cloud region, and averaging many requests reduces noise. Fixing it costs one function call, so the argument is not about how likely the attack is.
What to call in common languages
Python documents hmac.compare_digest for exactly this. The docs recommend it instead of the equals operator when comparing the output of digest() to an externally supplied digest, and note that it avoids content-based short circuiting.
import hmac, hashlib
def verify(key: bytes, msg: bytes, received_hex: str) -> bool:
expected = hmac.new(key, msg, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, received_hex)
Most other ecosystems ship an equivalent in the standard library or the crypto module. Look for names containing "constant time", "timing safe" or "secure compare". If you cannot find one, use your crypto library's own verify function instead of comparing raw bytes yourself, since verify functions usually do the safe comparison internally.
Rules that matter more than the function name
- Compare fixed-length values. Python's docs point out that differing lengths can reveal length information, though not the values. Hash both sides first, or compare fixed-size MAC outputs, so length is not a signal.
- Compare the computed MAC to the received one, never the other way around through a lookup that branches on content.
- Do not look up the secret by the supplied value in a way that takes a different path for hits and misses. Looking up a reset token in a database by its hash is fine, because the attacker cannot control the hash output.
- Treat a failed comparison the same as any other failure: same status code, same message, similar work.
Where this shows up in real code
Webhook receivers are the most common place. You compute an HMAC over the body and compare it with a header. If you wrote that header check with an equals operator, change it today. Other spots are session token checks, API key checks, signed URL checks and CSRF token checks.
Rate limits and lockouts reduce the practical risk further, but they do not replace the right comparison.
Try it yourself
Click through it at your own pace, or open it full screen. Look at how each result names the exact place to fix.
Quick check
Do I need constant time when comparing password hashes?
Use your password hashing library's verify function. It handles the comparison for you, so you should not compare stored hashes by hand.
Is a constant-time compare enough to make a webhook check safe?
No. You also need a strong secret, a MAC over the raw body, and ideally a timestamp check to limit replays. The comparison is one part of the design.
Sources
Last reviewed: 19 October 2026.