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