Skip to content

Commit be33ec6

Browse files
committed
Render style tag content more strictly.
This addresses a vulnerability where policies that allow `<style>` elements with text in `<option>` elements are vulnerable to XSS as disclosed in https://docs.google.com/document/d/11SoX296sMS0XoQiQbpxc5pNxSdbJKDJkm5BDv0zrX50/edit?usp=sharing This changes behavior for rendering of `<style>` element text so may change behavior. Specifically, `<style>` element text that includes the strings `-->` or `]]>` will no longer sanitize.
1 parent ad287c3 commit be33ec6

File tree

6 files changed

+87
-4
lines changed

6 files changed

+87
-4
lines changed

docs/credits.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* rfamilya
1515
* robinhouston
1616
* sneha patil
17+
* tomanthony
1718
* vytah
1819
* willikins_bear
1920
* yangbongsoo

docs/cve202142575.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# CVE-2021-42575
2+
3+
Policies that allow `<style>` tags inside `<option>` elements are vulnerable to RCE
4+
5+
See https://docs.google.com/document/d/11SoX296sMS0XoQiQbpxc5pNxSdbJKDJkm5BDv0zrX50/edit?usp=sharing for mitigations.

docs/vulnerabilities.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
# Known & public vulnerabilities in this project
1+
# Known & public vulnerabilities in this project
22

3+
* [CVE-2021-42575](cve202142575.md) - 18 Oct. 2021 - Recommend upgrade to latest version.
34
* [CVE-2011-4457](cve20114457.md) - 17 Nov. 2011 - Recommend upgrade to r88 or later.

src/main/java/org/owasp/html/HtmlStreamRenderer.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,15 @@
2929
package org.owasp.html;
3030

3131
import com.google.common.annotations.VisibleForTesting;
32+
import com.google.common.collect.ImmutableSet;
33+
3234
import java.io.Closeable;
3335
import java.io.Flushable;
3436
import java.io.IOException;
37+
import java.util.Collections;
3538
import java.util.Iterator;
3639
import java.util.List;
40+
import java.util.Set;
3741
import javax.annotation.WillCloseWhenClosed;
3842
import javax.annotation.concurrent.NotThreadSafe;
3943

@@ -250,7 +254,26 @@ private final void writeCloseTag(String uncanonElementName)
250254
Encoding.stripBannedCodeunits(cdataContent);
251255
int problemIndex = checkHtmlCdataCloseable(lastTagOpened, cdataContent);
252256
if (problemIndex == -1) {
253-
output.append(cdataContent);
257+
String prefix = "";
258+
String suffix = "";
259+
Set<String> bannedSubstrings = Collections.emptySet();
260+
if ("style".equals(elementName)) {
261+
prefix = "/*<![CDATA[<!--*/\n";
262+
suffix = "\n/*-->]]>*/";
263+
bannedSubstrings = BANNED_IN_STYLE_ELEMENTS;
264+
}
265+
266+
for (String bannedSubstring : bannedSubstrings) {
267+
if (cdataContent.indexOf(bannedSubstring) >= 0) {
268+
cdataContent.setLength(0);
269+
}
270+
}
271+
272+
if (cdataContent.length() != 0) {
273+
output.append(prefix);
274+
output.append(cdataContent);
275+
output.append(suffix);
276+
}
254277
} else {
255278
error(
256279
"Invalid CDATA text content",
@@ -434,4 +457,8 @@ public void close() throws IOException {
434457
private static boolean isTagEnd(char ch) {
435458
return ch < 63 && 0 != (TAG_ENDS & (1L << ch));
436459
}
460+
461+
private static Set<String> BANNED_IN_STYLE_ELEMENTS = ImmutableSet.of(
462+
"<![CDATA[", "]]>", "<!--", "-->"
463+
);
437464
}

src/test/java/org/owasp/html/SanitizersTest.java

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,53 @@ public static final void testStyleTagInTable() {
434434
pf.sanitize(input));
435435
}
436436

437+
@Test
438+
public static final void testStyleTagsInAllTheWrongPlaces() {
439+
String input = ""
440+
+ "<select><option><style><script>alert(1)</script></style></option></select>"
441+
+ "<svg><style>.r { color: red }</style></svg>"
442+
+ "<style>.b { color: blue }</style>"
443+
+ "<style>#a { content: \"<!--\" }</style>"
444+
+ "<style>#a { content: \"<![CDATA[\" }</style>"
445+
+ "<style>#a { content: \"-->\" }</style>"
446+
+ "<style>#a { content: \"]]>\" }</style>";
447+
PolicyFactory pf = new HtmlPolicyBuilder()
448+
.allowElements("option", "select", "style", "svg")
449+
.allowTextIn("style")
450+
.toFactory();
451+
assertEquals(
452+
""
453+
+ "<select><option>"
454+
+ "<style>/*<![CDATA[<!--*/\n<script>alert(1)</script>\n/*-->]]>*/</style>"
455+
+ "</option></select>"
456+
+ "<svg>"
457+
+ "<style>/*<![CDATA[<!--*/\n.r { color: red }\n/*-->]]>*/</style>"
458+
+ "</svg>"
459+
+ "<style>/*<![CDATA[<!--*/\n.b { color: blue }\n/*-->]]>*/</style>"
460+
+ "<style></style>"
461+
+ "<style></style>"
462+
+ "<style></style>"
463+
+ "<style></style>",
464+
pf.sanitize(input)
465+
);
466+
}
467+
468+
@Test
469+
public static final void testSelectIsOdd() {
470+
String input = "<select><option><xmp><script>alert(1)</script></xmp></option></select>";
471+
PolicyFactory pf = new HtmlPolicyBuilder()
472+
.allowElements("option", "select", "xmp")
473+
.allowTextIn("xmp")
474+
.toFactory();
475+
assertEquals(
476+
""
477+
+ "<select><option>"
478+
+ "<pre>&lt;script&gt;alert(1)&lt;/script&gt;</pre>"
479+
+ "</option></select>",
480+
pf.sanitize(input)
481+
);
482+
}
483+
437484
@Test
438485
public static final void testStyleGlobally() {
439486
PolicyFactory policyBuilder = new HtmlPolicyBuilder()
@@ -449,7 +496,7 @@ static int fac(int n) {
449496
int ifac = 1;
450497
for (int i = 1; i <= n; ++i) {
451498
int ifacp = ifac * i;
452-
if (ifacp < ifac) { throw new IllegalArgumentException("undeflow"); }
499+
if (ifacp < ifac) { throw new IllegalArgumentException("underflow"); }
453500
ifac = ifacp;
454501
}
455502
return ifac;

src/test/java/org/owasp/html/TagBalancingHtmlStreamRendererTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,9 @@ public final void testTextContent() {
158158
+ "<p>Hello, <textarea>World!</textarea></p>"
159159
+ "<h1>Hello"
160160
// Text allowed in special style tag.
161-
+ "<style type=\"text/css\">\n.World {\n color: blue\n}\n</style></h1>"
161+
+ "<style type=\"text/css\">/*<![CDATA[<!--*/\n"
162+
+ "\n.World {\n color: blue\n}\n"
163+
+ "\n/*-->]]>*/</style></h1>"
162164
// Whitespace allowed inside <ul> but non-whitespace text nodes are
163165
// moved inside <li>.
164166
+ "<ul><li>Hello,</li><li>World!</li></ul>",

0 commit comments

Comments
 (0)