openai/openai-python · error · InvalidWebhookSignatureError

Webhook timestamp is too new

Error message

Webhook timestamp is too new

What it means

webhook_signature_matches rejects webhooks whose timestamp is further in the future than the tolerance window, indicating a stale signed payload being replayed against a newer context or severe clock skew on the receiver.

Source

Thrown at src/openai/lib/_webhooks.py:37

) -> bool:
    """Validate the replay window and compare the supplied signatures."""
    signature_header = get_required_header(headers, "webhook-signature")
    timestamp = get_required_header(headers, "webhook-timestamp")
    webhook_id = get_required_header(headers, "webhook-id")

    # Validate timestamp to prevent replay attacks
    try:
        timestamp_seconds = int(timestamp)
    except ValueError:
        raise InvalidWebhookSignatureError("Invalid webhook timestamp format") from None

    now = int(time.time())

    if now - timestamp_seconds > tolerance:
        raise InvalidWebhookSignatureError("Webhook timestamp is too old") from None

    if timestamp_seconds > now + tolerance:
        raise InvalidWebhookSignatureError("Webhook timestamp is too new") from None

    # Extract signatures from v1,<base64> format
    # The signature header can have multiple values, separated by spaces.
    # Each value is in the format v1,<base64>. We should accept if any match.
    signatures: list[str] = []
    for part in signature_header.split():
        if part.startswith("v1,"):
            signatures.append(part[3:])
        else:
            signatures.append(part)

    # Decode the secret if it starts with whsec_
    if secret.startswith("whsec_"):
        decoded_secret = base64.b64decode(secret[6:])
    else:
        decoded_secret = secret.encode()

    body = payload.decode("utf-8") if isinstance(payload, bytes) else payload

View on GitHub (pinned to 9917c6e28e)

Solutions

  1. Correct the receiver's system clock via NTP
  2. Log both the header timestamp and local time when this fires to diagnose skew direction
  3. If skew is expected in your infra, increase tolerance explicitly rather than disabling verification

Example fix

// n/a (infrastructure fix)
# example: widen tolerance only if justified
webhook_signature_matches(body, headers, secret, tolerance=600)
Defensive patterns

Strategy: try-catch

Validate before calling

ts = int(headers["webhook-timestamp"])
import time
if ts > time.time() + tolerance:
    logger.warning("receiver clock behind sender by %ss", ts - time.time())

Try / catch

try:
    ok = webhook_signature_matches(body, headers, secret)
except InvalidWebhookSignatureError as e:
    if "too new" in str(e):
        return Response(401)
    raise

Prevention

When it happens

Trigger: timestamp_seconds > now + tolerance: receiving host's clock behind the sender, or a forged/manipulated timestamp header.

Common situations: Clock drift on the webhook receiver server; VMs resumed from snapshots with stale clocks; tampered payloads during attack attempts.

Related errors


AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28). Data as JSON: /api/errors/3055a1c5a0b5231a. Report an issue: GitHub.