Skip to content

Commit ef81048

Browse files
Merge commit from fork
* fix: Use `devalue.uneval` to serialize `hydratable` keys * oops
1 parent 6d90b96 commit ef81048

File tree

4 files changed

+30
-1
lines changed

4 files changed

+30
-1
lines changed

.changeset/tasty-vans-repeat.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: use `devalue.uneval` to serialize `hydratable` keys

packages/svelte/src/internal/server/renderer.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { BLOCK_CLOSE, BLOCK_OPEN } from './hydration.js';
1010
import { attributes } from './index.js';
1111
import { get_render_context, with_render_context, init_render_context } from './render-context.js';
1212
import { sha256 } from './crypto.js';
13+
import * as devalue from 'devalue';
1314

1415
/** @typedef {'head' | 'body'} RendererType */
1516
/** @typedef {{ [key in RendererType]: string }} AccumulatedContent */
@@ -669,7 +670,7 @@ export class Renderer {
669670
for (const p of v.promises) await p;
670671
}
671672

672-
entries.push(`[${JSON.stringify(k)},${v.serialized}]`);
673+
entries.push(`[${devalue.uneval(k)},${v.serialized}]`);
673674
}
674675

675676
let prelude = `const h = (window.__svelte ??= {}).h ??= new Map();`;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
skip_no_async: true,
5+
mode: ['hydrate'],
6+
7+
props: {
8+
key: '</script><script>throw new Error("pwned")</script>'
9+
},
10+
11+
async test() {
12+
// this test will fail when evaluating the `head` script if the vulnerability is present
13+
}
14+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
import { hydratable } from "svelte";
3+
4+
const { key } = $props();
5+
6+
const value = await hydratable(key, () => Promise.resolve('safe'));
7+
</script>
8+
9+
<p>{value}</p>

0 commit comments

Comments
 (0)