CWE-208, Observable Timing Discrepancy, is the case where two operations take different amounts of time in a way an outsider can observe, and the difference reveals something security-relevant, such as whether an operation succeeded.
MITRE notes that even small timing variations can be exploited to infer details of a product's internals. In some cryptographic algorithms, timing differences help an attacker infer properties of a private key and make it easier to guess. These differences form a timing side channel.
Anyone who compares secrets, verifies signatures, checks passwords or implements cryptography can introduce it.
How it happens
The usual cause is early exit. A loop that returns the moment it sees a mismatch finishes sooner for a wrong first byte than for a wrong last byte. Another cause is skipping work on the failure path.
The records MITRE lists show both:
- CVE-2019-10071: a Java-oriented framework compares HMAC signatures using String.equals() instead of a constant-time algorithm.
- CVE-2019-10482: a smartphone OS uses comparison functions that are not constant time, allowing side channels.
- CVE-2014-0984: a router's password-checking function stops validating at the first incorrect character, which lets remote attackers obtain passwords via brute force.
- CVE-2003-0078: an SSL implementation does not perform a MAC computation when block cipher padding is wrong, a timing discrepancy that may make cryptographic attacks easier.
Vulnerable pattern
// Vulnerable: String.equals stops at the first differing character
boolean valid = expectedSignature.equals(providedSignature);
// Vulnerable: memcmp may return as soon as bytes differ
if (memcmp(expected_mac, provided_mac, 32) == 0) { accept(); }
Over many requests, an attacker averages out network noise and learns how many leading bytes were right. Then they guess the next one.
What an attacker gains
MITRE lists confidentiality, access control and protection mechanism bypass. Concretely, the attacker can forge a valid signature or recover a password one position at a time, without ever seeing the secret. Against cryptographic code, timing can help narrow down a key.
How to find it
MITRE does not list detection methods for this entry. Use these checks.
- Search your code for comparisons of secrets: HMACs, tokens, session IDs, password hashes, API keys. Look for
==,equals,memcmp,strcmp. - Check each login and verify path for work that only happens on success or only on failure.
- Review dependencies that handle authentication or crypto. The two real-world examples above were library or platform code, not application code. A free in-browser dependency scan lists known CVEs in up to 100 dependencies without a login, and the file stays on your machine.
- Where it matters, measure. Send many requests with guesses that differ in how many leading bytes are right and compare the response times statistically.
How to fix it
Use the comparison function your platform provides for secrets, and do the same work on every path.
import java.security.MessageDigest;
import java.nio.charset.StandardCharsets;
boolean valid = MessageDigest.isEqual(
expectedSignature.getBytes(StandardCharsets.UTF_8),
providedSignature.getBytes(StandardCharsets.UTF_8));
import hmac
valid = hmac.compare_digest(expected_mac, provided_mac)
// Use a constant-time routine from your crypto library, for example
// CRYPTO_memcmp in OpenSSL, instead of memcmp.
if (CRYPTO_memcmp(expected_mac, provided_mac, 32) == 0) { accept(); }
Beyond the comparison:
- Compute the MAC or hash even when an earlier check has already failed, so the failure path does not run faster.
- Compare hashes of the values rather than the raw values where the library offers it.
- Add rate limits on verify endpoints. They do not remove the leak but they limit how many samples an attacker can take.
- Keep libraries updated so fixes in the comparison code reach you.
Quick check
Why not just add a random delay?
Random noise can be averaged out with enough samples. A constant-time comparison removes the signal instead of hiding it.
Does this only matter for cryptographic code?
No. Password checks and token comparisons in ordinary application code are common places for it, as the router password example shows.