1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
import { describe, expect, it } from "vitest";
import { sanitizeBadgeWallCss } from "./sanitizeCss";
describe("sanitizeBadgeWallCss", () => {
// Behaviour gate: the CSS people actually write for their badge wall survives.
it("preserves ordinary rules, declarations and values", () => {
const out = sanitizeBadgeWallCss(
".badge { color: red; opacity: 0.5; border-radius: 8px; }",
);
expect(out).toContain("color");
expect(out).toContain("red");
expect(out).toContain("border-radius");
});
it("preserves backdrop-filter, content, url() and at-rules", () => {
expect(
sanitizeBadgeWallCss(".x { backdrop-filter: blur(4px); }"),
).toContain("backdrop-filter");
expect(sanitizeBadgeWallCss('.x::before { content: "★"; }')).toContain(
"content",
);
expect(
sanitizeBadgeWallCss(
".x { background: url(https://cdn.due.moe/a.png); }",
),
).toContain("url(https://cdn.due.moe/a.png)");
expect(
sanitizeBadgeWallCss("@media (min-width: 1px) { .x { color: blue; } }"),
).toContain("@media");
expect(
sanitizeBadgeWallCss(
"@keyframes spin { from { transform: rotate(0); } to { transform: rotate(360deg); } }",
),
).toContain("@keyframes");
});
it("returns empty string for nullish input", () => {
expect(sanitizeBadgeWallCss("")).toBe("");
// @ts-expect-error exercising defensive nullish handling
expect(sanitizeBadgeWallCss(undefined)).toBe("");
});
// The fix: dangerous constructs are removed while surrounding CSS is kept.
it("strips @import, behavior, -moz-binding, expression and js: urls", () => {
const imported = sanitizeBadgeWallCss(
"@import url(https://evil.example.com/x.css); .x { color: red; }",
);
expect(imported).not.toContain("@import");
expect(imported).toContain("color");
expect(
sanitizeBadgeWallCss(".x { behavior: url(evil.htc); color: red; }"),
).not.toContain("behavior");
expect(
sanitizeBadgeWallCss(".x { -moz-binding: url(evil.xml#x); }"),
).not.toContain("-moz-binding");
expect(
sanitizeBadgeWallCss(".x { width: expression(alert(1)); }"),
).not.toContain("expression");
expect(
sanitizeBadgeWallCss(".x { background: url(javascript:alert(1)); }"),
).not.toContain("javascript:");
});
it("drops <style> break-out attempts entirely", () => {
const out = sanitizeBadgeWallCss(
".a { color: red; } </style><script>window.x=1</script> .b { color: blue; }",
);
expect(out).not.toContain("<script");
expect(out).not.toContain("</style");
expect(out).not.toContain("window.x");
expect(out).toContain("color");
});
});
|