Skip to content

Infinite loop in email._header_value_parser._fold_mime_parameters when parameter names are too long #138223

Open

Description

@TauPan

Bug report

Bug description:

Tested with 3.6 and 3.13.1

>>> import email.message
>>> message = email.message.EmailMessage()
...
>>> message.add_attachment('Hello World!', filename='hello.txt', params={130 * 'A': 'too long parameter name'})
None
>>> message.defects
[]
>>> message
<email.message.EmailMessage object at 0x7fe78ec74ec0>
>>> message.as_string()

130 characters for a media type parameter name is (a bit) more than https://datatracker.ietf.org/doc/html/rfc6838#section-4.3 allows but I didn't expect it to lead into an infinite loop. I wanted to check if the email module would catch that defect, which apparently it doesn't.

Distribution is openSUSE Leap 15.6, python 3.13.1 was installed from pyenv, 3.6 is from the distribution. The python3.11 binary from the distribution exhibits the same behaviour.

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Linked PRs

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    on Aug 28, 2025
  2. changed the title [-]email.message.EmailMessage().add_attachmen with too long key in params causes infinite loop in as_string()[/-] [+]email.message.EmailMessage().add_attachment with too long key in params causes infinite loop in as_string()[/+] on Aug 28, 2025
  3. StanFromIreland commented on Aug 28, 2025

    @StanFromIreland
  4. StanFromIreland commented on Aug 28, 2025

    @StanFromIreland
    Member

    Potentially a duplicate of #136063

  5. StanFromIreland commented on Aug 28, 2025

    @StanFromIreland
    Member

    I can reproduce for length $\ge 62$

  6. picnixz commented on Aug 28, 2025

    @picnixz
  7. picnixz commented on Aug 28, 2025

    @picnixz
    Member

    Ok, I understand what happens. The issue is with folding. For instance:

    m = email.message.EmailMessage()
    m.add_attachment('Hello World!', filename='hello.txt', params={'a' * 64: 'abc'})
    m.as_string()

    works perfectly. But changing 'abc' into something else (maybe longer) looks to make it an infinite loop. And I think it's a true infinite loop here. For instance, using abc def 123 instead makes it an infinite loop.

  8. picnixz commented on Aug 28, 2025

    @picnixz
    Member

    The fix is in _fold_mime_parameters where while True should be replaced by while splitpoint >= 1 and we should forcibly write the line even if we cannot do it in this case (or do whatever the RFC tells us to do)

  9. changed the title [-]email.message.EmailMessage().add_attachment with too long key in params causes infinite loop in as_string()[/-] [+]Infinite loop in `email._header_value_parser._fold_mime_parameters` when parameter names are too long[/+] on Aug 28, 2025
  10. bedevere-app commented on Aug 28, 2025

    @bedevere-app
  11. StanFromIreland commented on Aug 28, 2025

    @StanFromIreland
  12. picnixz commented on Aug 28, 2025

    @picnixz
  13. StanFromIreland commented on Aug 28, 2025

    @StanFromIreland
  14. TauPan commented on Aug 29, 2025

    @TauPan
    Author

    This is also, probably unsurprisingly, triggered by parsing an email with email.policy.default. It's not triggered with the compat32 policy:

    >>> import email.message
    >>> mail_string='''MIME-Version: 1.0
    Content-Type: multipart/mixed; boundary="usuvtu4gckda5fud"
    Content-Disposition: inline
    
    --usuvtu4gckda5fud
    Content-Type: text/plain; charset=us-ascii;
            AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=abc
    Content-Disposition: attachment; filename="hello.txt"
    
    Hello World!
    
    --usuvtu4gckda5fud--
    '''
    >>> m = email.message_from_string(mail_string, policy=email.policy.compat32)
    >>> m.as_string()
  15. picnixz commented on Aug 29, 2025

    @picnixz
    Member

    Yes, that's because the compat32 policy has a different way to fold thing. The default policy detects that the tokenlist is the part containing MIME parameters so it calls _fold_mime_parameters() which is buggy. For the compat32 policy, we don't hit this (we don't even enter _refold_parse_tree() I think?)

  16. added a commit that references this issue on Aug 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytopic-emailtype-bugAn unexpected behavior, bug, or errortype-securityA security issue

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions