#3701·tornado

decode_signed_value raises ValueError for authenticated malformed timestamps

Author: yingying9025123-codeCreated Aug 4, 2026Updated Sep 6, 2026
markdown
   `decode_signed_value` raises `ValueError` for a syntactically malformed
   timestamp after the cookie signature has been successfully verified.

   I expected an invalid signed cookie to be rejected with `None`, consistent
   with `RequestHandler.get_signed_cookie`'s documented return behavior, rather
   than causing an exception in request handling.

   ## Reproducer

   This example constructs a structurally valid v2 signed value whose timestamp
   field is `b"a"` and computes a valid HMAC using the configured secret:

   ```python
   from tornado.escape import utf8
   from tornado.web import _create_signature_v2, decode_signed_value

   def field(value: bytes) -> bytes:
       return str(len(value)).encode("ascii") + b":" + value

   secret = b"s"
   name = "a"

   prefix = b"|".join(
       [
           b"2",
           field(b"0"),
           field(b"a"),       # non-decimal timestamp
           field(utf8(name)),
           field(b""),
           b"",
       ]
   )
   cookie = prefix + _create_signature_v2(secret, prefix)

   assert decode_signed_value(
       secret, name, cookie, clock=lambda: 1_500_000_000
   ) is None

Actual result

  ValueError: invalid literal for int() with base 10: b'a'
The exception is raised by:

```python
  timestamp = int(timestamp_bytes)

in _decode_signed_value_v2.

Expected result

Return None for this invalid cookie, without raising. Scope / impact

This is not a signature-bypass issue: constructing this particular input requires a valid signing key. However, it means a malformed cookie produced by a key-holding component (or after a key compromise/migration issue) can cause get_signed_cookie to raise and potentially turn a request into a 500 instead of treating the cookie as invalid.

I also observed an analogous uncaught ValueError path in the legacy v1 decoder after signature verification, so a fix may want to cover both v1 and v2 timestamp conversions.

Tested on current master (e530031) and release v6.5.7.