CVE-2024-26151: Insufficient Information (NVD-CWE-noinfo)
value: The `mjml` PyPI package, found at the `FelixSchwarz/mjml-python` GitHub repo, is an unofficial Python port of MJML, a markup language created by Mailjet. All users of `FelixSchwarz/mjml-python` who insert untrusted data into mjml templates unless that data is checked in a very strict manner. User input like `&lt;script&gt;` would be rendered as `<script>` in the final HTML output. The attacker must be able to control some data which is later injected in an mjml template which is then send out as email to other users. The attacker could control contents of email messages sent through the platform. The problem has been fixed in version 0.11.0 of this library. Versions before 0.10.0 are not affected by this security issue. As a workaround, ensure that potentially untrusted user input does not contain any sequences which could be rendered as HTML.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-02-22T19:15Z
Repository: https://github.com/FelixSchwarz/mjml-python
Language: Python
Files changed: CHANGELOG.md, mjml/mjml2html.py, tests/testdata/css-inlining-expected.html, tests/testdata/css-inlining.mjml
Commit date: 2023-11-17 18:55:56 +0100
Commit message: Fix CSS child selectors; don't load remote stylesheets

Diff: diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2c1e62c..2265b21 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,9 +1,11 @@
 
 0.10.0 (?)
 ------------------
 
+- fix CSS child selectors
+- disable loading remote stylesheets
 - require css-inline 0.11.x for performance improvements
 - drop css-inline Python 3.6 support
 - fix exception when processing an `mj-section` with `background-size` (reported by Thomas Handorf)
 
 
diff --git a/mjml/mjml2html.py b/mjml/mjml2html.py
index 029e808..437b75e 100644
--- a/mjml/mjml2html.py
+++ b/mjml/mjml2html.py
@@ -113,11 +113,11 @@ def mjml_to_html(xml_fp_or_json, skeleton=None, template_dir=None,
             attributes = _mjml.attrs
             children = [child for child in _mjml]
             classes = ignore_empty(attributes.get('mj-class', '').split(' '))
 
             # upstream parses text contents (+ comments) in mjml-parser-xml/index.js
-            content = _mjml.decode_contents()
+            content = _mjml.decode_contents(formatter=None)
 
             attributesClasses = {}
             for css_class in classes:
                 mjClassValues = globalDatas.classes.get(css_class)
                 if mjClassValues:
@@ -210,11 +210,11 @@ def mjml_to_html(xml_fp_or_json, skeleton=None, template_dir=None,
         for selector, data in globalDatas.htmlAttributes.items():
             for attrName, value in data.items():
                 for element in contentSoup.select(selector):
                     element[attrName] = value or ''
 
-        content = contentSoup.decode_contents()
+        content = contentSoup.decode_contents(formatter=None)
 
     content = skeleton(
         content=content,
         # upstream just passes this extra key to skeleton() as JavaScript
         # won't complain about additional parameters.
@@ -233,10 +233,11 @@ def mjml_to_html(xml_fp_or_json, skeleton=None, template_dir=None,
         inliner = css_inline.CSSInliner(
             extra_css=extra_css,
             inline_style_tags=False,
             keep_link_tags=True,
             keep_style_tags=True,
+            load_remote_stylesheets=False,
         )
         content = inliner.inline(content)
 
     content = mergeOutlookConditionnals(content)
 
diff --git a/tests/testdata/css-inlining-expected.html b/tests/testdata/css-inlining-expected.html
index 39ce267..0085077 100644
--- a/tests/testdata/css-inlining-expected.html
+++ b/tests/testdata/css-inlining-expected.html
@@ -122,11 +122,11 @@
 </td></tr></table><![endif]-->
                       </td>
                     </tr>
                     <tr>
                       <td align="left" class="box" style="border: 5px solid red; font-size: 0px; padding: 10px 25px; word-break: break-word;">
-                        <div style="font-family:helvetica;font-size:20px;line-height:1;text-align:left;color:#F45E43;">Hello World</div>
+                        <div style="font-family:helvetica;font-size:20px;line-height:1;text-align:left;color:#F45E43;"><span style="border: 3px solid blue;"> &lt; Hello World &gt; </span></div>
                       </td>
                     </tr>
                   </tbody>
                 </table>
               </div>
diff --git a/tests/testdata/css-inlining.mjml b/tests/testdata/css-inlining.mjml
index 538a0eb..f7fcf06 100644
--- a/tests/testdata/css-inlining.mjml
+++ b/tests/testdata/css-inlining.mjml
@@ -2,21 +2,28 @@
   <mj-head>
     <mj-style inline="inline">
       .box {
         border: 5px solid red;
       }
+      .box > div > span {
+        border: 3px solid blue;
+      }
     </mj-style>
   </mj-head>
   <mj-body>
     <mj-section>
       <mj-column>
 
         <mj-image width="100px" src="/assets/img/logo-small.png"></mj-image>
 
         <mj-divider border-color="#F45E43"></mj-divider>
 
-        <mj-text css-class="box" font-size="20px" color="#F45E43" font-family="helvetica">Hello World</mj-text>
+        <mj-text css-class="box" font-size="20px" color="#F45E43" font-family="helvetica">
+          <span>
+            &lt; Hello World &gt;
+          </span>
+        </mj-text>
 
       </mj-column>
     </mj-section>
   </mj-body>
 </mjml>

Vulnerable code:             content = _mjml.decode_contents()
        content = contentSoup.decode_contents()
                        <div style="font-family:helvetica;font-size:20px;line-height:1;text-align:left;color:#F45E43;">Hello World</div>
        <mj-text css-class="box" font-size="20px" color="#F45E43" font-family="helvetica">Hello World</mj-text>
Fixed code: - fix CSS child selectors
- disable loading remote stylesheets
            content = _mjml.decode_contents(formatter=None)
        content = contentSoup.decode_contents(formatter=None)
            load_remote_stylesheets=False,
                        <div style="font-family:helvetica;font-size:20px;line-height:1;text-align:left;color:#F45E43;"><span style="border: 3px solid blue;"> &lt; Hello World &gt; </span></div>
      .box > div > span {
        border: 3px solid blue;
      }
        <mj-text css-class="box" font-size="20px" color="#F45E43" font-family="helvetica">
          <span>
            &lt; Hello World &gt;
          </span>
        </mj-text>