Skip to content

Commit 85e995f

Browse files
committed
Improve the sanitization test
Now also covers the case where an in-memory element attempts to run a script before it has been added to the DOM.
1 parent 1ff01a5 commit 85e995f

File tree

2 files changed

+42
-9
lines changed

2 files changed

+42
-9
lines changed

test-server/public/import4.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
img.dangerous[onload="console.log('danger')"] {
2-
content: 'image.png';
1+
img[onerror="event.target.classList.add('xss'), console.log('xss')"] {
2+
content: '';
33
}

tests/sanitize.spec.ts

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ div.last[onclick="console.log('foo')"] {
1515
`;
1616

1717
test('Sanitization Off', async ({ page }) => {
18+
const consoleMessages = new Array<string>();
19+
page.on('console', message => consoleMessages.push(message.text()));
1820
await page.goto('http://localhost:5173/');
1921
const body = await page.evaluate(async (css) => { document.body = await cssToHtml(css, { imports: 'include', sanitize: 'off' }); return document.body.outerHTML; }, css);
2022

@@ -34,9 +36,14 @@ test('Sanitization Off', async ({ page }) => {
3436
const imgElement = await img.elementHandle();
3537
expect(imgElement).toBeTruthy();
3638

37-
// The img should have an `onload` attribute.
38-
const imgAttribute = await imgElement?.getAttribute('onload');
39-
expect(imgAttribute).toBe('console.log(\'danger\')');
39+
// The img should have an `onerror` attribute.
40+
const imgAttribute = await imgElement?.getAttribute('onerror');
41+
expect(imgAttribute).toBeDefined();
42+
expect(imgAttribute?.length).toBeGreaterThan(10);
43+
44+
// The img should have an `xss` class.
45+
const imgClass = await imgElement?.getAttribute('class');
46+
expect(imgClass).toBe('xss');
4047

4148
// There should be exactly one div element.
4249
const div = page.locator('div');
@@ -51,9 +58,14 @@ test('Sanitization Off', async ({ page }) => {
5158
// The div should have an `onclick` attribute.
5259
const divAttribute = await divElement?.getAttribute('onclick');
5360
expect(divAttribute).toBe('console.log(\'foo\')');
61+
62+
// An 'xss' console message should be present.
63+
expect(consoleMessages.includes('xss')).toBe(true);
5464
});
5565

5666
test('Sanitize Imports Only', async ({ page }) => {
67+
const consoleMessages = new Array<string>();
68+
page.on('console', message => consoleMessages.push(message.text()));
5769
await page.goto('http://localhost:5173/');
5870
const body = await page.evaluate(async (css) => { document.body = await cssToHtml(css, { imports: 'include', sanitize: 'imports' }); return document.body.outerHTML; }, css);
5971

@@ -73,10 +85,14 @@ test('Sanitize Imports Only', async ({ page }) => {
7385
const imgElement = await img.elementHandle();
7486
expect(imgElement).toBeTruthy();
7587

76-
// The img should not have an `onload` attribute.
77-
const imgAttribute = await imgElement?.getAttribute('onload');
88+
// The img should not have an `onerror` attribute.
89+
const imgAttribute = await imgElement?.getAttribute('onerror');
7890
expect(imgAttribute).toBeNull();
7991

92+
// The img should not have an `xss` class.
93+
const imgClass = await imgElement?.getAttribute('class');
94+
expect(imgClass).toBeNull();
95+
8096
// There should be exactly one div element.
8197
const div = page.locator('div');
8298
expect(await div.count()).toBe(1);
@@ -90,6 +106,9 @@ test('Sanitize Imports Only', async ({ page }) => {
90106
// The div should have an `onclick` attribute.
91107
const divAttribute = await divElement?.getAttribute('onclick');
92108
expect(divAttribute).toBe('console.log(\'foo\')');
109+
110+
// An 'xss' console message should not be present.
111+
expect(consoleMessages.includes('xss')).toBe(false);
93112
});
94113

95114
async function expectEverythingToBeSanitized (page: Page): Promise<void> {
@@ -109,10 +128,14 @@ async function expectEverythingToBeSanitized (page: Page): Promise<void> {
109128
const imgElement = await img.elementHandle();
110129
expect(imgElement).toBeTruthy();
111130

112-
// The img should not have an `onload` attribute.
113-
const imgAttribute = await imgElement?.getAttribute('onload');
131+
// The img should not have an `onerror` attribute.
132+
const imgAttribute = await imgElement?.getAttribute('onerror');
114133
expect(imgAttribute).toBeNull();
115134

135+
// The img should not have an `xss` class.
136+
const imgClass = await imgElement?.getAttribute('class');
137+
expect(imgClass).toBeNull();
138+
116139
// There should be exactly one div element.
117140
const div = page.locator('div');
118141
expect(await div.count()).toBe(1);
@@ -129,15 +152,25 @@ async function expectEverythingToBeSanitized (page: Page): Promise<void> {
129152
}
130153

131154
test('Sanitize Everything', async ({ page }) => {
155+
const consoleMessages = new Array<string>();
156+
page.on('console', message => consoleMessages.push(message.text()));
132157
await page.goto('http://localhost:5173/');
133158
const body = await page.evaluate(async (css) => { document.body = await cssToHtml(css, { imports: 'include', sanitize: 'all' }); return document.body.outerHTML; }, css);
134159

135160
await expectEverythingToBeSanitized(page);
161+
162+
// An 'xss' console message should not be present.
163+
expect(consoleMessages.includes('xss')).toBe(false);
136164
});
137165

138166
test('Sanitize Everything By Default', async ({ page }) => {
167+
const consoleMessages = new Array<string>();
168+
page.on('console', message => consoleMessages.push(message.text()));
139169
await page.goto('http://localhost:5173/');
140170
const body = await page.evaluate(async (css) => { document.body = await cssToHtml(css, { imports: 'include' }); return document.body.outerHTML; }, css);
141171

142172
await expectEverythingToBeSanitized(page);
173+
174+
// An 'xss' console message should not be present.
175+
expect(consoleMessages.includes('xss')).toBe(false);
143176
});

0 commit comments

Comments
 (0)