Files
chatwoot/app/mailboxes/mailbox_sanitizer.rb
d1c482cb64 fix(email): strip null bytes from inbound mailbox messages (#14546)
Inbound emails containing null bytes could fail while Chatwoot persisted
the incoming message, causing IMAP sync to drop and repeatedly retry the
same malformed email. This strips null bytes at the inbound mailbox
message persistence boundary so the rest of the email can be saved
normally.

Fixes
https://linear.app/chatwoot/issue/CW-7165/argumenterror-string-contains-null-byte-argumenterror
Sentry: https://chatwoot-p3.sentry.io/issues/7405946944/

## Test
- [x] added specs
- [x] manually tested the logic on prod for the inbox(email) which was
throwing the error

## What changed

- Sanitizes null bytes only while building attributes for inbound
mailbox message persistence.
- Uses the sanitized source ID for both duplicate lookup and message
creation.
- Adds regression coverage for the mailbox message creation path.

---------

Co-authored-by: Sony Mathew <2040199+sony-mathew@users.noreply.github.com>
Co-authored-by: Sony Mathew <sony@chatwoot.com>
2026-06-08 17:12:25 +05:30

35 lines
962 B
Ruby

module MailboxSanitizer
NULL_BYTE = "\u0000".freeze
private
def sanitized_message_attributes(source_id)
{
account_id: @conversation.account_id,
sender: @conversation.contact,
content: sanitize_mailbox_value(mail_content)&.truncate(150_000),
inbox_id: @conversation.inbox_id,
message_type: 'incoming',
content_type: 'incoming_email',
source_id: source_id,
content_attributes: sanitized_content_attributes
}
end
def sanitized_content_attributes
sanitize_mailbox_value(
email: processed_mail.serialized_data,
cc_email: processed_mail.cc,
bcc_email: processed_mail.bcc
)
end
def sanitize_mailbox_value(value)
return value.delete(NULL_BYTE) if value.is_a?(String)
return value.map { |item| sanitize_mailbox_value(item) } if value.is_a?(Array)
return value.transform_values { |item| sanitize_mailbox_value(item) } if value.is_a?(Hash)
value
end
end