Skip to content

Commit a6fb00d

Browse files
authored
Merge commit from fork
* Fix xss vulnerability in javascript template strings * Escape dollar signs to prevent undesired interpolation
1 parent 0c7d4ad commit a6fb00d

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

jte-runtime/src/main/java/gg/jte/html/escape/Escape.java

+4
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ public static void javaScriptBlock(String value, TemplateOutput output) {
4949
switch (c) {
5050
case '\'' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\'", output);
5151
case '"' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\\"", output);
52+
case '`' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\`", output);
53+
case '$' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\$", output);
5254
case '/' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\/", output);
5355
case '-' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\-", output);
5456
case '\\' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\\\", output);
@@ -73,6 +75,8 @@ public static void javaScriptAttribute(String value, TemplateOutput output) {
7375
switch (c) {
7476
case '\'' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\x27", output);
7577
case '"' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\x22", output);
78+
case '`' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\x60", output);
79+
case '$' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\x24", output);
7680
case '\\' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\\\", output);
7781
case '\n' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\n", output);
7882
case '\t' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\t", output);

jte/src/test/java/gg/jte/TemplateEngine_HtmlOutputEscapingTest.java

+82
Original file line numberDiff line numberDiff line change
@@ -1313,6 +1313,88 @@ void invalidAttribute_semicolon() {
13131313
assertThat(throwable).isInstanceOf(TemplateException.class).hasMessage("Failed to compile template.jte, error at line 1: Invalid HTML attribute name ;!");
13141314
}
13151315

1316+
@Test
1317+
void templateStringInJavaScriptBlock_backtick() {
1318+
codeResolver.givenCode("template.jte", """
1319+
@param String someMessage
1320+
<!DOCTYPE html>
1321+
<html lang="en">
1322+
<head>
1323+
<title>XSS Test</title>
1324+
<script>window.someVariable = `${someMessage}`;</script>
1325+
</head>
1326+
<body>
1327+
<h1>XSS Test</h1>
1328+
</body>
1329+
</html>
1330+
""");
1331+
1332+
templateEngine.render("template.jte", "` + alert(`xss`) + `", output);
1333+
1334+
assertThat(output.toString()).isEqualTo("""
1335+
<!DOCTYPE html>
1336+
<html lang="en">
1337+
<head>
1338+
<title>XSS Test</title>
1339+
<script>window.someVariable = `\\` + alert(\\`xss\\`) + \\``;</script>
1340+
</head>
1341+
<body>
1342+
<h1>XSS Test</h1>
1343+
</body>
1344+
</html>
1345+
""");
1346+
}
1347+
1348+
@Test
1349+
void templateStringInJavaScriptBlock_dollar() {
1350+
codeResolver.givenCode("template.jte", """
1351+
@param String someMessage
1352+
<!DOCTYPE html>
1353+
<html lang="en">
1354+
<head>
1355+
<title>XSS Test</title>
1356+
<script>window.someVariable = `${someMessage}`;</script>
1357+
</head>
1358+
<body>
1359+
<h1>XSS Test</h1>
1360+
</body>
1361+
</html>
1362+
""");
1363+
1364+
templateEngine.render("template.jte", "${secret}", output);
1365+
1366+
assertThat(output.toString()).isEqualTo("""
1367+
<!DOCTYPE html>
1368+
<html lang="en">
1369+
<head>
1370+
<title>XSS Test</title>
1371+
<script>window.someVariable = `\\${secret}`;</script>
1372+
</head>
1373+
<body>
1374+
<h1>XSS Test</h1>
1375+
</body>
1376+
</html>
1377+
""");
1378+
}
1379+
1380+
@Test
1381+
void templateStringInJavaScriptAttribute_backtick() {
1382+
codeResolver.givenCode("template.jte", "@param String p\n<span onClick=\"console.log(`${p}`)\">foo</span>");
1383+
1384+
templateEngine.render("template.jte", "` + alert(`xss`) + `", output);
1385+
1386+
assertThat(output.toString()).isEqualTo("<span onClick=\"console.log(`\\x60 + alert(\\x60xss\\x60) + \\x60`)\">foo</span>");
1387+
}
1388+
1389+
@Test
1390+
void templateStringInJavaScriptAttribute_dollar() {
1391+
codeResolver.givenCode("template.jte", "@param String p\n<span onClick=\"console.log(`${p}`)\">foo</span>");
1392+
1393+
templateEngine.render("template.jte", "${secret}", output);
1394+
1395+
assertThat(output.toString()).isEqualTo("<span onClick=\"console.log(`\\x24{secret}`)\">foo</span>");
1396+
}
1397+
13161398
@Test
13171399
void localization_notFound_noParams() {
13181400
codeResolver.givenCode("template.jte", """

0 commit comments

Comments
 (0)