File tree 5 files changed +58
-5
lines changed
5 files changed +58
-5
lines changed Original file line number Diff line number Diff line change @@ -2,7 +2,7 @@ import devalue from 'devalue';
2
2
import { readable , writable } from 'svelte/store' ;
3
3
import { coalesce_to_error } from '../../../utils/error.js' ;
4
4
import { hash } from '../../hash.js' ;
5
- import { escape_html_attr , escape_json_string_in_html } from '../../../utils/escape.js' ;
5
+ import { escape_html_attr , escape_json_in_html } from '../../../utils/escape.js' ;
6
6
import { s } from '../../../utils/misc.js' ;
7
7
import { create_prerendering_url_proxy } from './utils.js' ;
8
8
import { Csp , csp_ready } from './csp.js' ;
@@ -261,7 +261,7 @@ export async function render_response({
261
261
262
262
if ( shadow_props ) {
263
263
// prettier-ignore
264
- body += `<script type="application/json" data-type="svelte-props">${ escape_json_string_in_html ( s ( shadow_props ) ) } </script>` ;
264
+ body += `<script type="application/json" data-type="svelte-props">${ escape_json_in_html ( s ( shadow_props ) ) } </script>` ;
265
265
}
266
266
}
267
267
Original file line number Diff line number Diff line change 1
1
/** @type {Record<string, string> } */
2
- const escape_json_string_in_html_dict = {
3
- '"' : '\\"' ,
2
+ const escape_json_in_html_dict = {
4
3
'<' : '\\u003C' ,
5
4
'>' : '\\u003E' ,
6
5
'/' : '\\u002F' ,
@@ -15,7 +14,38 @@ const escape_json_string_in_html_dict = {
15
14
'\u2029' : '\\u2029'
16
15
} ;
17
16
18
- /** @param {string } str */
17
+ /** @type {Record<string, string> } */
18
+ const escape_json_string_in_html_dict = {
19
+ '"' : '\\"' ,
20
+ ...escape_json_in_html_dict
21
+ } ;
22
+
23
+ /**
24
+ * escape a json string to be embedded into a script data tag
25
+ *
26
+ * <script>
27
+ * output here
28
+ * </script>
29
+ * @param {string } str
30
+ */
31
+ export function escape_json_in_html ( str ) {
32
+ return escape (
33
+ str ,
34
+ escape_json_in_html_dict ,
35
+ ( code ) => `\\u${ code . toString ( 16 ) . toUpperCase ( ) } `
36
+ ) ;
37
+ }
38
+
39
+ /**
40
+ * escape a json string to be embedded into a larger json object thats going to be embedded in html
41
+ *
42
+ * <script>
43
+ * {
44
+ * "foo":"output here"
45
+ * }
46
+ * </script>
47
+ * @param {string } str
48
+ */
19
49
export function escape_json_string_in_html ( str ) {
20
50
return escape (
21
51
str ,
Original file line number Diff line number Diff line change
1
+ /** @type {import('@sveltejs/kit').RequestHandler } */
2
+ export function get ( ) {
3
+ return {
4
+ body : {
5
+ pwned : '</script><script>window.pwned = 1</script>'
6
+ }
7
+ } ;
8
+ }
Original file line number Diff line number Diff line change
1
+ <script >
2
+ export let pwned;
3
+ </script >
4
+ <h1 >failed script inject is: {pwned }</h1 >
5
+
Original file line number Diff line number Diff line change @@ -1992,4 +1992,14 @@ test.describe.parallel('XSS', () => {
1992
1992
// @ts -expect-error - check global injected variable
1993
1993
expect ( await page . evaluate ( ( ) => window . pwned ) ) . toBeUndefined ( ) ;
1994
1994
} ) ;
1995
+
1996
+ test ( 'no xss via shadow endpoint' , async ( { page } ) => {
1997
+ await page . goto ( '/xss/shadow' )
1998
+
1999
+ // @ts -expect-error - check global injected variable
2000
+ expect ( await page . evaluate ( ( ) => window . pwned ) ) . toBeUndefined ( ) ;
2001
+ expect ( await page . textContent ( 'h1' ) ) . toBe (
2002
+ 'failed script inject is: </script><script>window.pwned = 1</script>'
2003
+ ) ;
2004
+ } ) ;
1995
2005
} ) ;
You can’t perform that action at this time.
0 commit comments