From a686b1a7aac321d7f3ebfa452c65836f718238b0 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 21 Jul 2026 13:01:34 -0700 Subject: [PATCH] Fix: bound email linkification work --- src/paperless/parsers/mail.py | 11 +++++++- .../tests/parsers/test_mail_parser.py | 28 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/paperless/parsers/mail.py b/src/paperless/parsers/mail.py index 8188b7933..8e3123992 100644 --- a/src/paperless/parsers/mail.py +++ b/src/paperless/parsers/mail.py @@ -58,6 +58,12 @@ _SUPPORTED_MIME_TYPES: dict[str, str] = { "message/rfc822": ".eml", } +# Bleach's email-address linkifier uses a superlinear regular expression. Keep +# email linkification for ordinary headers and short messages, but never run it +# over an unbounded attacker-controlled field. URL linkification remains enabled +# for longer text. +_MAX_EMAIL_LINKIFY_LENGTH = 2048 + class MailDocumentParser: """Parse .eml email files for Paperless-ngx. @@ -627,7 +633,10 @@ class MailDocumentParser: text = str(text) text = escape(text) text = clean(text) - text = linkify(text, parse_email=True) + text = linkify( + text, + parse_email="@" in text and len(text) <= _MAX_EMAIL_LINKIFY_LENGTH, + ) text = text.replace("\n", "
") return text diff --git a/src/paperless/tests/parsers/test_mail_parser.py b/src/paperless/tests/parsers/test_mail_parser.py index b875442ad..8c28a6a03 100644 --- a/src/paperless/tests/parsers/test_mail_parser.py +++ b/src/paperless/tests/parsers/test_mail_parser.py @@ -700,6 +700,34 @@ class TestParser: assert expected_html == actual_html + def test_mail_to_html_bounds_email_linkification( + self, + mail_parser: MailDocumentParser, + ) -> None: + mail = mock.Mock( + subject="sender@example.com", + from_values=None, + to_values=[], + cc_values=[], + bcc_values=[], + attachments=[], + date=timezone.now(), + text=("a." * 1500) + "@example.com", + ) + + with mock.patch( + "paperless.parsers.mail.linkify", + side_effect=lambda text, **kwargs: text, + ) as mock_linkify: + mail_parser.mail_to_html(mail) + + parse_email_by_text = { + call.args[0]: call.kwargs["parse_email"] + for call in mock_linkify.call_args_list + } + assert parse_email_by_text["sender@example.com"] is True + assert parse_email_by_text[mail.text] is False + def test_generate_pdf_from_mail( self, httpx_mock: HTTPXMock,