Skip to content

Commit

Permalink
Merge commit from fork
Browse files Browse the repository at this point in the history
* Fix xss vulnerability in javascript template strings

* Escape dollar signs to prevent undesired interpolation
  • Loading branch information
casid authored Jan 13, 2025
1 parent 0c7d4ad commit a6fb00d
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 0 deletions.
4 changes: 4 additions & 0 deletions jte-runtime/src/main/java/gg/jte/html/escape/Escape.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public static void javaScriptBlock(String value, TemplateOutput output) {
switch (c) {
case '\'' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\'", output);
case '"' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\\"", output);
case '`' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\`", output);
case '$' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\$", output);
case '/' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\/", output);
case '-' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\-", output);
case '\\' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\\\", output);
Expand All @@ -73,6 +75,8 @@ public static void javaScriptAttribute(String value, TemplateOutput output) {
switch (c) {
case '\'' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\x27", output);
case '"' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\x22", output);
case '`' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\x60", output);
case '$' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\x24", output);
case '\\' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\\\", output);
case '\n' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\n", output);
case '\t' -> lastIndex = flushAndEscape(value, lastIndex, i, "\\t", output);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,88 @@ void invalidAttribute_semicolon() {
assertThat(throwable).isInstanceOf(TemplateException.class).hasMessage("Failed to compile template.jte, error at line 1: Invalid HTML attribute name ;!");
}

@Test
void templateStringInJavaScriptBlock_backtick() {
codeResolver.givenCode("template.jte", """
@param String someMessage
<!DOCTYPE html>
<html lang="en">
<head>
<title>XSS Test</title>
<script>window.someVariable = `${someMessage}`;</script>
</head>
<body>
<h1>XSS Test</h1>
</body>
</html>
""");

templateEngine.render("template.jte", "` + alert(`xss`) + `", output);

assertThat(output.toString()).isEqualTo("""
<!DOCTYPE html>
<html lang="en">
<head>
<title>XSS Test</title>
<script>window.someVariable = `\\` + alert(\\`xss\\`) + \\``;</script>
</head>
<body>
<h1>XSS Test</h1>
</body>
</html>
""");
}

@Test
void templateStringInJavaScriptBlock_dollar() {
codeResolver.givenCode("template.jte", """
@param String someMessage
<!DOCTYPE html>
<html lang="en">
<head>
<title>XSS Test</title>
<script>window.someVariable = `${someMessage}`;</script>
</head>
<body>
<h1>XSS Test</h1>
</body>
</html>
""");

templateEngine.render("template.jte", "${secret}", output);

assertThat(output.toString()).isEqualTo("""
<!DOCTYPE html>
<html lang="en">
<head>
<title>XSS Test</title>
<script>window.someVariable = `\\${secret}`;</script>
</head>
<body>
<h1>XSS Test</h1>
</body>
</html>
""");
}

@Test
void templateStringInJavaScriptAttribute_backtick() {
codeResolver.givenCode("template.jte", "@param String p\n<span onClick=\"console.log(`${p}`)\">foo</span>");

templateEngine.render("template.jte", "` + alert(`xss`) + `", output);

assertThat(output.toString()).isEqualTo("<span onClick=\"console.log(`\\x60 + alert(\\x60xss\\x60) + \\x60`)\">foo</span>");
}

@Test
void templateStringInJavaScriptAttribute_dollar() {
codeResolver.givenCode("template.jte", "@param String p\n<span onClick=\"console.log(`${p}`)\">foo</span>");

templateEngine.render("template.jte", "${secret}", output);

assertThat(output.toString()).isEqualTo("<span onClick=\"console.log(`\\x24{secret}`)\">foo</span>");
}

@Test
void localization_notFound_noParams() {
codeResolver.givenCode("template.jte", """
Expand Down

0 comments on commit a6fb00d

Please sign in to comment.