mirror of https://github.com/sveltejs/svelte
https://github.com/sveltejs/svelte/security/advisories/GHSA-f3cj-j4f6-wq85 Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>pull/18220/head
parent
d2375e2ebc
commit
a16ebc67bb
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: prevent XSS on `hydratable` from user contents
|
||||
@ -0,0 +1,33 @@
|
||||
import { afterAll, beforeAll, expect, test } from 'vitest';
|
||||
import { Renderer } from './renderer.js';
|
||||
import type { Component } from 'svelte';
|
||||
import { disable_async_mode_flag, enable_async_mode_flag } from '../flags/index.js';
|
||||
import { hydratable } from './hydratable.js';
|
||||
|
||||
beforeAll(() => {
|
||||
enable_async_mode_flag();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
disable_async_mode_flag();
|
||||
});
|
||||
|
||||
test('treats replacement tokens in hydratable promise values as literals', async () => {
|
||||
const component = (renderer: Renderer) => {
|
||||
hydratable('key', () => Promise.resolve(`$'`));
|
||||
renderer.child(async () => {
|
||||
await Promise.resolve();
|
||||
});
|
||||
renderer.push('ok');
|
||||
};
|
||||
|
||||
const { head } = await Renderer.render(component as unknown as Component);
|
||||
const script_match = head.match(/<script(?:\s[^>]*)?>([\s\S]*)<\/script>/);
|
||||
|
||||
expect(script_match, 'expected hydratable script in head output').toBeTruthy();
|
||||
|
||||
const script_content = script_match![1];
|
||||
expect(script_content).toContain('const h = (window.__svelte ??= {}).h ??= new Map();');
|
||||
expect(script_content).toContain('r("$\'")');
|
||||
expect(script_content).toMatch(/\[\s*"key"\s*,\s*r\("\$'"\)\s*\]/);
|
||||
});
|
||||
Loading…
Reference in new issue