Skip to content

PYTHON-5873 Reject whitespace in ObjectId hex strings - #3134

Open
GoldenEmperor1177 wants to merge 1 commit into
mongodb:mainfrom
GoldenEmperor1177:PYTHON-5873
Open

GoldenEmperor1177 wants to merge 1 commit into
mongodb:mainfrom
GoldenEmperor1177:PYTHON-5873

Conversation

@GoldenEmperor1177

Copy link
Copy Markdown

PYTHON-5873

Changes in this PR

ObjectId(str) only checked that the string has 24 characters, but
bytes.fromhex() skips ASCII whitespace. So ObjectId("0123 0011")
created an ObjectId shorter than 12 bytes, and ObjectId(" " * 24) created an
empty one. ObjectId.is_valid() returned True for them, and
generation_time raised struct.error.

The fix checks the length of the decoded bytes as well, so these strings raise
InvalidId. A string that decodes to 12 bytes has 24 hex digits, so it cannot
contain whitespace, and only inputs that previously produced broken ObjectIds
change behaviour. No API change. Added a changelog entry.

AI disclosure: I used an AI assistant (Claude Code) to help find the cause,
write the fix and the tests. I read the change and I understand it.

Test Plan

Added test_from_hex_whitespace and two cases in test_is_valid in
test/test_objectid.py. They fail without the fix and pass with it. I also ran
the other tests that don't need a server (test_bson, test_json_util,
test_bson_corpus, test_dbref, test_son, test_binary, test_code,
test_decimal128, test_timestamp), and ruff, ruff format and mypy on
the changed files. I did not run the tests that need a running mongod.

Checklist

Checklist for Author

  • Did you update the changelog (if necessary)?
  • Is there test coverage?
  • Is any followup work tracked in a JIRA ticket? If so, add link(s).

Checklist for Reviewer

  • Does the title of the PR reference a JIRA Ticket?
  • Do you fully understand the implementation? (Would you be comfortable explaining how this code works to someone else?)
  • Is all relevant documentation (README or docstring) updated?

bytes.fromhex() skips ASCII whitespace, and ObjectId only checked that
the string has 24 characters. A string like "0123                0011"
therefore created an ObjectId shorter than 12 bytes, and a string of 24
spaces created an empty one. ObjectId.is_valid() returned True for
them, and ObjectId.generation_time raised struct.error.

Check the length of the decoded bytes too, so such strings raise
InvalidId.
@GoldenEmperor1177
GoldenEmperor1177 requested a review from a team as a code owner October 17, 2026 15:47

@NoahStapp NoahStapp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution! Two small test changes, otherwise great!

Comment thread test/test_objectid.py
Comment on lines +66 to +69
# The string form of an ObjectId round-trips.
oid = ObjectId()
self.assertEqual(oid, ObjectId(str(oid)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't related to the rest of the test. Existing tests already verify that ObjectId round-trips, and the ObjectId being created here doesn't contain any whitespace.

Comment thread test/test_objectid.py
Comment on lines +167 to +168
self.assertFalse(ObjectId.is_valid("0123 0011"))
self.assertFalse(ObjectId.is_valid(" " * 24))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.assertFalse(ObjectId.is_valid("0123 0011"))
self.assertFalse(ObjectId.is_valid(" " * 24))
self.assertFalse(ObjectId.is_valid("0123 0011"))
self.assertFalse(ObjectId.is_valid("00 " * 8))
self.assertFalse(ObjectId.is_valid("01\n" * 8))
self.assertFalse(ObjectId.is_valid(" " * 24))

Consistency across both test cases.

@NoahStapp
NoahStapp removed the request for review from sleepyStick October 20, 2026 13:47

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants