skills/igbuend/grimbard/timing-attacks-anti-pattern

timing-attacks-anti-pattern

SKILL.md

Timing Attacks Anti-Pattern

Severity: Medium

Summary

Attackers measure operation timing to extract secrets. Early-exit comparisons leak information: comparing ABCDEF to ABCDEG takes longer than ABCDEF to XBCDEF (more matching characters before mismatch). These timing differences enable character-by-character secret recovery.

The Anti-Pattern

The anti-pattern is comparison functions returning early upon finding differences in sensitive values (passwords, tokens, hashes).

BAD Code Example

# VULNERABLE: String comparison leaking timing information.

def insecure_compare(s1, s2):
    # Exits on first mismatch (early exit).
    # First character mismatch returns quickly.
    # Last character mismatch takes longer.
    if len(s1) != len(s2):
        return False
    for i in range(len(s1)):
        if s1[i] != s2[i]:
            return False # Early exit leaks timing.
    return True

SECRET_TOKEN = "abcdef123456"

@app.route("/check_token")
def check_token():
    provided_token = request.args.get("token")
    if insecure_compare(provided_token, SECRET_TOKEN):
        return "Token valid!"
    return "Token invalid!"

# Attack: Measure response times to discover secret character-by-character.
# token=X -> fast (first char wrong)
# token=a -> slower (first char matches)
# token=ab -> even slower (two chars match)

GOOD Code Example

# SECURE: Constant-time comparison prevents timing leaks.
import hmac
import secrets

def secure_compare(s1_bytes, s2_bytes):
    # `hmac.compare_digest` performs constant-time comparison.
    # Execution time depends only on length, not values.
    # Always compares all bytes.
    return hmac.compare_digest(s1_bytes, s2_bytes)

SECRET_TOKEN = secrets.token_bytes(16) # Secure 128-bit token.

@app.route("/check_token_secure")
def check_token_secure():
    provided_token_hex = request.args.get("token")
    try:
        provided_token_bytes = bytes.fromhex(provided_token_hex)
    except ValueError:
        return "Token invalid!", 400

    # Length check handled safely by compare_digest.
    if len(provided_token_bytes) != len(SECRET_TOKEN):
        return "Token invalid!", 400

    if secure_compare(provided_token_bytes, SECRET_TOKEN):
        return "Token valid!"
    return "Token invalid!"

Detection

  • Review code for secret comparisons: Look for any place in the code where sensitive values (passwords, API keys, session tokens, cryptographic hashes, HMAC signatures) are compared.
  • Identify standard equality operators: Search for == or === being used for comparing secrets. These operators are typically not constant-time.
  • Look for custom comparison loops: If a custom loop iterates through characters and returns False on the first mismatch, it's vulnerable.

Prevention

  • Use constant-time comparison for secrets: Never use standard equality operators for sensitive values.
  • Know constant-time functions:
    • Python: hmac.compare_digest() or secrets.compare_digest()
    • Node.js: crypto.timingSafeEqual()
    • Go: subtle.ConstantTimeCompare()
    • Java: MessageDigest.isEqual() (byte arrays)
    • PHP: hash_equals()
  • Use password library verification: Libraries like bcrypt/argon2 provide timing-safe verification (bcrypt.checkpw(), argon2.verify()).
  • Verify equal lengths: Constant-time functions handle length mismatches safely, but pre-checking improves clarity.

Related Security Patterns & Anti-Patterns

References

Weekly Installs
3
GitHub Stars
4
First Seen
Feb 19, 2026
Installed on
openclaw3
claude-code3
replit3
codex3
kiro-cli3
kimi-cli3