Skip to content

fix(sanitize): decode and sanitize bytes fields in sanitize_dict - #316

Merged
chigwell merged 1 commit into
chigwell:mainfrom
axisrow:ao/telegram-mcp-4/up-305
Oct 16, 2026
Merged

chigwell merged 1 commit into
chigwell:mainfrom
axisrow:ao/telegram-mcp-4/up-305

Conversation

@axisrow

@axisrow axisrow commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Summary

sanitize_dict sanitized only str values; bytes fields were decoded later by _json_default at serialization time — after the sanitization point. The same control byte was stripped from str fields but survived raw in bytes fields, then round-tripped back out through format_tool_result(...) → json.loads.

sanitize_dict now decodes bytes (UTF-8, replacing errors) at the sanitization point and sanitizes them as text, so both field types get identical treatment. _json_default stays as the last resort for bytes that reach json.dumps without passing through sanitize_dict.

Fixes #305

Before

from telegram_mcp.sanitize import sanitize_user_content, sanitize_dict

sanitize_user_content('\x1b[31mRED')   # '[31mRED'  (ESC stripped, as designed)
sanitize_dict({'b': b'\x1b[31mRED'})   # {'b': b'\x1b[31mRED'}  (ESC survived)

format_tool_result(...) then round-tripped the raw ESC sequence back out through json.loads — identical content got different treatment depending on the field type.

After

sanitize_dict({'b': b'\x1b[31mRED'})   # {'b': '[31mRED'}  (ESC stripped, same as str)
sanitize_dict({'b': b'caf\xc3\xa9\x00'})  # {'b': 'café'}  (decoded, control bytes stripped)

Bytes fields now return sanitized str — the same shape _json_default produced at serialization time, so the final JSON output is unchanged except that control bytes are gone.

Tests

  • tests/test_sanitize.py::TestSanitizeDict::test_bytes_values_are_decoded_and_sanitized — ESC byte stripped from a bytes field, valid UTF-8 payload (café\x00) decoded and cleaned.
  • Full suite: pytest -q → 1216 passed.

Risks

  • sanitize_dict output type changes for bytes fields: bytes → sanitized str. This matches the final JSON serialization shape; no caller in the repo relies on bytes surviving sanitize_dict.

🤖 Generated with Claude Code

sanitize_dict sanitized only str values; bytes fields were decoded
later by _json_default at serialization time, i.e. after the
sanitization point, so a control byte stripped from str fields
survived raw in bytes fields.

Decode bytes (UTF-8, replacing errors) inside sanitize_dict so both
field types get identical treatment. _json_default stays as the last
resort for bytes that reach json.dumps without passing sanitize_dict.

Co-Authored-By: Claude Code <[email protected]>
@chigwell
chigwell merged commit 3cd1fa8 into chigwell:main Oct 16, 2026
4 checks passed
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.

sanitize_dict does not sanitize control characters in bytes fields

2 participants