From dee2cf1d1d87fbd480818c6bd7b9711e120a05b8 Mon Sep 17 00:00:00 2001 From: Madan Kumar Date: Sun, 26 Jul 2026 05:41:57 +0530 Subject: [PATCH] PYTHON-XXXX Reject extra fields in JSON timestamps --- bson/json_util.py | 2 ++ doc/changelog.rst | 2 ++ doc/contributors.rst | 1 + test/test_json_util.py | 12 ++++++++++++ 4 files changed, 17 insertions(+) diff --git a/bson/json_util.py b/bson/json_util.py index 098a4b18ce..f01cd6cd19 100644 --- a/bson/json_util.py +++ b/bson/json_util.py @@ -789,6 +789,8 @@ def _parse_binary(doc: Any, json_options: JSONOptions) -> Union[Binary, uuid.UUI def _parse_timestamp(doc: Any, dummy0: Any) -> Timestamp: tsp = doc["$timestamp"] + if set(tsp) != {"t", "i"}: + raise TypeError(f'$timestamp must include exactly "t" and "i" components: {doc}') return Timestamp(tsp["t"], tsp["i"]) diff --git a/doc/changelog.rst b/doc/changelog.rst index c272714376..cda288c575 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -25,6 +25,8 @@ PyMongo 4.18 brings a number of changes including: the bytes remaining in the array now raises :class:`~bson.errors.InvalidBSON` instead of reading past the end of the buffer. +- Fixed :func:`bson.json_util.loads` to reject ``$timestamp`` values containing + fields other than ``t`` and ``i``. Changes in Version 4.17.0 (2026/04/20) -------------------------------------- diff --git a/doc/contributors.rst b/doc/contributors.rst index d36731159e..6c2cff68a3 100644 --- a/doc/contributors.rst +++ b/doc/contributors.rst @@ -109,3 +109,4 @@ The following is a list of people who have contributed to - Noah Stapp (NoahStapp) - Cal Jacobson (cj81499) - Sophia Yang (sophiayangDB) +- Madan Kumar (winklemad) diff --git a/test/test_json_util.py b/test/test_json_util.py index cd86456ab0..f1b781d3d9 100644 --- a/test/test_json_util.py +++ b/test/test_json_util.py @@ -405,6 +405,18 @@ def test_timestamp(self): self.assertEqual(dct, rtdct) self.assertEqual('{"ts": {"$timestamp": {"t": 4, "i": 13}}}', res) + def test_timestamp_with_invalid_fields(self): + invalid_values = [ + '{"t": 4, "i": 13, "extra": 1}', + '{"t": 4, "unexpected": 13}', + ] + for value in invalid_values: + with self.subTest(value=value): + with self.assertRaisesRegex( + TypeError, r'\$timestamp must include exactly "t" and "i" components' + ): + json_util.loads(f'{{"ts": {{"$timestamp": {value}}}}}') + def test_uuid_default(self): # Cannot directly encode native UUIDs with the default # uuid_representation.