CVE-2022-31103 (published 2022-06-27T23:15Z)

lettersanitizer is a DOM-based HTML email sanitizer for in-browser email rendering. All versions of lettersanitizer below 1.0.2 are affected by a denial of service issue when processing a CSS at-rule `@keyframes`. This package is depended on by [react-letter](https://github.com/mat-sz/react-letter), therefore everyone using react-letter is also at risk. The problem has been patched in version 1.0.2.

Severity: MEDIUM
CVSS v2 base score: 5.0 (AV:N/AC:L/Au:N/C:N/I:N/A:P)
CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-754
cwe_name: Improper Check for Unusual or Exceptional Conditions
description: The product does not check or incorrectly checks for unusual or exceptional conditions that are not expected to occur frequently during day to day operation of the product.
extended_description: 
            The programmer may assume that certain events or conditions will never occur or do not need to be worried about, such as low memory conditions, lack of access to resources due to restrictive permissions, or misbehaving clients or components. However, attackers may intentionally trigger these unusual conditions, thus violating the programmer's assumptions, possibly introducing instability, incorrect behavior, or a vulnerability.
            Note that this entry is not exclusively about the use of exceptions and exception handling, which are mechanisms for both checking and handling unusual or unexpected conditions.
         
         

Fix information:
repo_url: https://github.com/mat-sz/lettersanitizer
commit_details: repo_url: https://github.com/mat-sz/lettersanitizer
author: Mat Sz
author_date: 2022-06-22 18:10:29+02:00
msg: filter out unsupported at-rules
repository: repo_url: https://github.com/mat-sz/lettersanitizer
repo_name: mat-sz/lettersanitizer
description: 📧 DOM-based HTML email sanitizer for in-browser email rendering.
repo_language: TypeScript
owner: mat-sz
file_changes: filename: sanitize.test.ts
change_type: ModificationType.MODIFY
diff: @@ -295,4 +295,59 @@ b {background: red;}</style>`,
     ).toBe(`<style>a {background: red;}
 b {background: red;}</style>`);
   });
+
+  it('removes @keyframes rules from CSS', () => {
+    expect(
+      sanitize(
+        `<style>@keyframes test {
+          0% {
+              transform: rotate(0deg);
+          }
+
+          100% {
+              transform: rotate(360deg);
+          }
+        }</style>`,
+        '',
+        { noWrapper: true, preserveCssPriority: false }
+      )
+    ).toBe(`<style></style>`);
+  });
+
+  it('removes @supports rules from CSS', () => {
+    expect(
+      sanitize(
+        `<style>@supports (display: grid) {
+            div {
+              display: grid;
+            }
+          }</style>`,
+        '',
+        { noWrapper: true, preserveCssPriority: false }
+      )
+    ).toBe(`<style></style>`);
+  });
+
+  it('removes @font-face rules from CSS', () => {
+    expect(
+      sanitize(
+        `<style>@font-face {
+            font-family: "Open Sans";
+            src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2"),
+                 url("/fonts/OpenSans-Regular-webfont.woff") format("woff");
+          }</style>`,
+        '',
+        { noWrapper: true, preserveCssPriority: false }
+      )
+    ).toBe(`<style></style>`);
+  });
+
+  it('removes @import rules from CSS', () => {
+    expect(
+      sanitize(`<style>@import 'custom.css';</style>`, '', {
+        noWrapper: true,
+        preserveCssPriority: false,
+      })
+    ).toBe(`<style></style>`);
+  });
 });

programming_language: JavaScript
filename: index.ts
change_type: ModificationType.MODIFY
diff: @@ -307,7 +307,9 @@ function sanitizeHtml(
           rewriteExternalResources
         );
         newRules.push(rule);
-      } else if ('cssRules' in rule) {
+      } else if ('cssRules' in rule && 'media' in rule) {
+        // According to https://www.caniemail.com/,
+        // out of all at-rules, Gmail only supports @media.
         const mediaRule = (rule as any) as CSSMediaRule;
         const newRulesMedia: CSSRule[] = [];
 

programming_language: TypeScript