diff --git a/.changeset/tasty-vans-repeat.md b/.changeset/tasty-vans-repeat.md new file mode 100644 index 0000000000..d95e8de7e7 --- /dev/null +++ b/.changeset/tasty-vans-repeat.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: use `devalue.uneval` to serialize `hydratable` keys diff --git a/packages/svelte/src/internal/server/renderer.js b/packages/svelte/src/internal/server/renderer.js index 1ecc90ba1f..82f8025759 100644 --- a/packages/svelte/src/internal/server/renderer.js +++ b/packages/svelte/src/internal/server/renderer.js @@ -10,6 +10,7 @@ import { BLOCK_CLOSE, BLOCK_OPEN } from './hydration.js'; import { attributes } from './index.js'; import { get_render_context, with_render_context, init_render_context } from './render-context.js'; import { sha256 } from './crypto.js'; +import * as devalue from 'devalue'; /** @typedef {'head' | 'body'} RendererType */ /** @typedef {{ [key in RendererType]: string }} AccumulatedContent */ @@ -669,7 +670,7 @@ export class Renderer { for (const p of v.promises) await p; } - entries.push(`[${JSON.stringify(k)},${v.serialized}]`); + entries.push(`[${devalue.uneval(k)},${v.serialized}]`); } let prelude = `const h = (window.__svelte ??= {}).h ??= new Map();`; diff --git a/packages/svelte/tests/runtime-runes/samples/hydratable-script-escape/_config.js b/packages/svelte/tests/runtime-runes/samples/hydratable-script-escape/_config.js new file mode 100644 index 0000000000..bc51795565 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/hydratable-script-escape/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + skip_no_async: true, + mode: ['hydrate'], + + props: { + key: '' + }, + + async test() { + // this test will fail when evaluating the `head` script if the vulnerability is present + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/hydratable-script-escape/main.svelte b/packages/svelte/tests/runtime-runes/samples/hydratable-script-escape/main.svelte new file mode 100644 index 0000000000..1327492190 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/hydratable-script-escape/main.svelte @@ -0,0 +1,9 @@ + + +
{value}