From 4a01c6716abdd966c52fb6457de1cfdaf14d1680 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Sun, 28 Jan 2024 15:47:22 +0100 Subject: [PATCH 1/6] Fix examples in README.md Signed-off-by: Sven Strickroth --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e6249953..657fdb0d 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ elements do not include any attributes. [Attribute policies](https://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/20220608.1/org/owasp/html/AttributePolicy.html) allow running custom code too. Adding an attribute policy will not water down any default policy like `style` or URL attribute checks. ```Java -new HtmlPolicyBuilder = new HtmlPolicyBuilder() +PolicyFactory myPolicy = new HtmlPolicyBuilder() .allowElement("div", "span") .allowAttributes("data-foo") .matching( @@ -96,7 +96,7 @@ new HtmlPolicyBuilder = new HtmlPolicyBuilder() // Return value for the attribute or null to drop. }) .onElements("div", "span") - .build() + .toFactory(); ``` ## Preprocessors @@ -104,9 +104,7 @@ new HtmlPolicyBuilder = new HtmlPolicyBuilder() Preprocessors allow inserting text and large scale structural changes. ```Java -new HtmlPolicyBuilder = new HtmlPolicyBuilder() - // Use a preprocessor to be backwards compatible with the - // element which +PolicyFactory myPolicy = new HtmlPolicyBuilder() .withPreprocessor( (HtmlStreamEventReceiver r) -> { // Provide user with info about links before they click. @@ -116,7 +114,7 @@ new HtmlPolicyBuilder = new HtmlPolicyBuilder() @Override public void openTag(String elementName, List<String> attrs) { if ("a".equals(elementName)) { for (int i = 0, n = attrs.size(); i < n; i += 2) { - if ("href".equals(attrs.get(i)) { + if ("href".equals(attrs.get(i))) { String url = attrs.get(i + 1); String origin; try { @@ -141,10 +139,12 @@ new HtmlPolicyBuilder = new HtmlPolicyBuilder() super.openTag(elementName, attrs); } }; - } - .allowElement("a") + }) + .allowElements("a") + .allowAttributes("href").onElements("a") + .allowStandardUrlProtocols() ... - .build() + .toFactory(); ``` From 246732e69998fc3f55707ad53dc0989625d28698 Mon Sep 17 00:00:00 2001 From: Domi <slickdomique@proton.me> Date: Wed, 22 Jan 2025 19:58:03 +0100 Subject: [PATCH 2/6] Allowing HTML attributes with _ as the first character in the name --- .../main/java/org/owasp/html/HtmlStreamRenderer.java | 4 +++- .../test/java/org/owasp/html/HtmlSanitizerTest.java | 10 +++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/owasp-java-html-sanitizer/src/main/java/org/owasp/html/HtmlStreamRenderer.java b/owasp-java-html-sanitizer/src/main/java/org/owasp/html/HtmlStreamRenderer.java index 7e657ee1..7d7a24d2 100644 --- a/owasp-java-html-sanitizer/src/main/java/org/owasp/html/HtmlStreamRenderer.java +++ b/owasp-java-html-sanitizer/src/main/java/org/owasp/html/HtmlStreamRenderer.java @@ -393,9 +393,11 @@ static boolean isValidHtmlName(String name) { if (i == 0 || i + 1 == n) { return false; } break; case '-': - case '_': if (i == 0 || i + 1 == n) { return false; } break; + case '_': + if (i + 1 == n) { return false; } + break; default: if (ch <= '9') { if (i == 0 || ch < '0') { return false; } diff --git a/owasp-java-html-sanitizer/src/test/java/org/owasp/html/HtmlSanitizerTest.java b/owasp-java-html-sanitizer/src/test/java/org/owasp/html/HtmlSanitizerTest.java index 1ff169df..b6693349 100644 --- a/owasp-java-html-sanitizer/src/test/java/org/owasp/html/HtmlSanitizerTest.java +++ b/owasp-java-html-sanitizer/src/test/java/org/owasp/html/HtmlSanitizerTest.java @@ -195,6 +195,13 @@ public static final void testEmptyAndValuelessAttributes() { sanitize("<input checked type=checkbox id=\"\" class=>")); } + @Test + public final void testAllowedAttributes() { + assertEquals( + "<div __foo=\"__foo\" __bar=\"foo\" foo-bar=\"foo-bar\"></div>", + sanitize("<div __foo __bar=\"foo\" foo-bar></div>")); + } + @Test public static final void testSgmlShortTags() { // We make no attempt to correctly handle SGML short tags since they are @@ -471,7 +478,8 @@ public void handle(String errorMessage) { "ol", "p", "span", "ul", "noscript", "noframes", "noembed", "noxss") // And these attributes. .allowAttributes( - "dir", "checked", "class", "href", "id", "target", "title", "type") + "dir", "checked", "class", "href", "id", "target", "title", "type", + "__foo", "__bar", "foo-bar") .globally() // Cleanup IDs and CLASSes and prefix them with p- to move to a separate // name-space. From e6e58fb39ea0634f6c74f6cb66fcbee65bdbe25d Mon Sep 17 00:00:00 2001 From: strangelookingnerd <49242855+strangelookingnerd@users.noreply.github.com> Date: Tue, 6 Jan 2026 15:44:02 +0100 Subject: [PATCH 3/6] Replace version ranges with latest versions (#370) --- owasp-java-html-sanitizer/pom.xml | 9 ++------- pom.xml | 16 +++++----------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/owasp-java-html-sanitizer/pom.xml b/owasp-java-html-sanitizer/pom.xml index c4597c03..0b612d17 100644 --- a/owasp-java-html-sanitizer/pom.xml +++ b/owasp-java-html-sanitizer/pom.xml @@ -104,13 +104,8 @@ <scope>test</scope> </dependency> <dependency> - <groupId>com.google.code.findbugs</groupId> - <artifactId>jsr305</artifactId> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>com.google.code.findbugs</groupId> - <artifactId>annotations</artifactId> + <groupId>com.github.spotbugs</groupId> + <artifactId>spotbugs-annotations</artifactId> <scope>provided</scope> </dependency> <dependency> diff --git a/pom.xml b/pom.xml index 6d9896d4..a65fca72 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ application while protecting against XSS. <licenses> <license> <name>Apache License, Version 2.0</name> - <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> + <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url> <distribution>repo</distribution> </license> </licenses> @@ -272,18 +272,12 @@ application while protecting against XSS. <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> - <version>[1.15,)</version> + <version>1.20.0</version> </dependency> <dependency> - <groupId>com.google.code.findbugs</groupId> - <artifactId>jsr305</artifactId> - <version>[2.0.1,)</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>com.google.code.findbugs</groupId> - <artifactId>annotations</artifactId> - <version>[2.0.1,)</version> + <groupId>com.github.spotbugs</groupId> + <artifactId>spotbugs-annotations</artifactId> + <version>4.9.8</version> <scope>provided</scope> </dependency> <dependency> From a447aa0c971f108a4b45f525bd85b9cfd6762d2c Mon Sep 17 00:00:00 2001 From: Daham Chinthana <dahamchinthana@adsl-dynamic-ipv6.slt.lk> Date: Sat, 7 Feb 2026 22:29:29 +0530 Subject: [PATCH 4/6] docs: update hardcoded Javadoc versions to 'latest' alias --- README.md | 2 +- docs/getting_started.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 34899311..fada8898 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ of the output. ## Telemetry -When a policy rejects an element or attribute it notifies an [HtmlChangeListener](https://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/20240325.1/org/owasp/html/HtmlChangeListener.html). +When a policy rejects an element or attribute it notifies an [HtmlChangeListener](https://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/latest/org/owasp/html/HtmlChangeListener.html). You can use this to keep track of policy violation trends and find out when someone is making an effort to breach your security. diff --git a/docs/getting_started.md b/docs/getting_started.md index d72c9232..305e0b76 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -29,16 +29,16 @@ it to HTML. The [javadoc](http://javadoc.io/doc/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/) covers more detailed topics, including -[customization](https://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/20240325.1/org/owasp/html/HtmlPolicyBuilder.html). +[customization](https://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/latest/org/owasp/html/HtmlPolicyBuilder.html). Important classes are: - * [Sanitizers](https://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/20240325.1/org/owasp/html/Sanitizers.html) contains combinable pre-packaged policies. - * [HtmlPolicyBuilder](https://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/20240325.1/org/owasp/html/HtmlPolicyBuilder.html) lets you easily build custom policies. + * [Sanitizers](https://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/latest/org/owasp/html/Sanitizers.html) contains combinable pre-packaged policies. + * [HtmlPolicyBuilder](https://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/latest/org/owasp/html/HtmlPolicyBuilder.html) lets you easily build custom policies. For advanced use, see: - * [AttributePolicy](https://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/20240325.1/org/owasp/html/AttributePolicy.html) and [ElementPolicy](http://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/20180219.1/org/owasp/html/ElementPolicy.html) allow complex customization. - * [HtmlStreamEventReceiver](https://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/20240325.1/org/owasp/html/HtmlStreamEventReceiver.html) if you don't just want a `String` as output. + * [AttributePolicy](https://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/latest/org/owasp/html/AttributePolicy.html) and [ElementPolicy](http://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/latest/org/owasp/html/ElementPolicy.html) allow complex customization. + * [HtmlStreamEventReceiver](https://static.javadoc.io/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/latest/org/owasp/html/HtmlStreamEventReceiver.html) if you don't just want a `String` as output. ## Asking Questions From c9546175fc2261d8b03fc4fbfdcfd709c65a1d6e Mon Sep 17 00:00:00 2001 From: hwangjeyeon <kingpele9018@gmail.com> Date: Mon, 2 Mar 2026 12:56:23 +0900 Subject: [PATCH 5/6] Feat: allow table span attributes and image loading attribute - Add colspan and rowspan support to TABLES policy with integer validation. - Add loading attribute to IMAGES policy with lazy and eager whitelist. - Relocate INTEGER AttributePolicy for shared use between TABLES and IMAGES. Signed-off-by: hwangjeyeon <kingpele9018@gmail.com> --- .../main/java/org/owasp/html/Sanitizers.java | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/owasp-java-html-sanitizer/src/main/java/org/owasp/html/Sanitizers.java b/owasp-java-html-sanitizer/src/main/java/org/owasp/html/Sanitizers.java index ed6f4d93..10379fe8 100644 --- a/owasp-java-html-sanitizer/src/main/java/org/owasp/html/Sanitizers.java +++ b/owasp-java-html-sanitizer/src/main/java/org/owasp/html/Sanitizers.java @@ -79,26 +79,9 @@ public final class Sanitizers { .allowAttributes("href").onElements("a").requireRelNofollowOnLinks() .toFactory(); - /** - * Allows common table elements. - */ - public static final PolicyFactory TABLES = new HtmlPolicyBuilder() - .allowStandardUrlProtocols() - .allowElements( - "table", "tr", "td", "th", - "colgroup", "caption", "col", - "thead", "tbody", "tfoot") - .allowAttributes("summary").onElements("table") - .allowAttributes("align", "valign") - .onElements("table", "tr", "td", "th", - "colgroup", "col", - "thead", "tbody", "tfoot") - .allowTextIn("table") // WIDGY - .toFactory(); - private static final AttributePolicy INTEGER = new AttributePolicy() { public String apply( - String elementName, String attributeName, String value) { + String elementName, String attributeName, String value) { int n = value.length(); if (n == 0) { return null; } for (int i = 0; i < n; ++i) { @@ -114,14 +97,34 @@ public String apply( } }; + /** + * Allows common table elements. + */ + public static final PolicyFactory TABLES = new HtmlPolicyBuilder() + .allowStandardUrlProtocols() + .allowElements( + "table", "tr", "td", "th", + "colgroup", "caption", "col", + "thead", "tbody", "tfoot") + .allowAttributes("summary").onElements("table") + .allowAttributes("align", "valign") + .onElements("table", "tr", "td", "th", + "colgroup", "col", + "thead", "tbody", "tfoot") + .allowAttributes("colspan", "rowspan").matching(INTEGER).onElements("td", "th") + .allowTextIn("table") // WIDGY + .toFactory(); + /** * Allows {@code <img>} elements from HTTP, HTTPS, and relative sources. + * Allows loading elements */ public static final PolicyFactory IMAGES = new HtmlPolicyBuilder() .allowUrlProtocols("http", "https").allowElements("img") .allowAttributes("alt", "src").onElements("img") .allowAttributes("border", "height", "width").matching(INTEGER) .onElements("img") + .allowAttributes("loading").matching(true, "lazy", "eager").onElements("img") .toFactory(); private Sanitizers() { From f42b1d11808999af71fb6a12914f5f46c2eb7a18 Mon Sep 17 00:00:00 2001 From: hwangjeyeon <kingpele9018@gmail.com> Date: Mon, 2 Mar 2026 12:56:42 +0900 Subject: [PATCH 6/6] Test: verify table span and image loading policies Signed-off-by: hwangjeyeon <kingpele9018@gmail.com> --- .../java/org/owasp/html/SanitizersTest.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/owasp-java-html-sanitizer/src/test/java/org/owasp/html/SanitizersTest.java b/owasp-java-html-sanitizer/src/test/java/org/owasp/html/SanitizersTest.java index 3b29e023..f98d70ad 100644 --- a/owasp-java-html-sanitizer/src/test/java/org/owasp/html/SanitizersTest.java +++ b/owasp-java-html-sanitizer/src/test/java/org/owasp/html/SanitizersTest.java @@ -156,6 +156,18 @@ public static final void testImages() { s.sanitize( "<img src=\"x.png\" alt=\"y\" width=\"widgy\" height=64 border=0>") ); + assertEquals( + "<img src=\"test.jpg\" loading=\"lazy\" />", + s.sanitize("<img src=\"test.jpg\" loading=\"lazy\">")); + assertEquals( + "<img src=\"test.jpg\" loading=\"eager\" />", + s.sanitize("<img src=\"test.jpg\" loading=\"eager\">")); + assertEquals( + "<img src=\"test.jpg\" />", + s.sanitize("<img src=\"test.jpg\" loading=\"auto\">")); + assertEquals( + "<img src=\"test.jpg\" />", + s.sanitize("<img src=\"test.jpg\" loading=\"javascript:alert(1337)\">")); } @Test @@ -210,6 +222,24 @@ public static final void testIntegerAttributePolicy() { ); } + @Test + public static final void testTableColspanRowspan() { + PolicyFactory s = Sanitizers.TABLES; + + assertEquals( + "<table><tbody><tr><td colspan=\"3\">cell</td></tr></tbody></table>", + s.sanitize("<table><tr><td colspan=\"3\">cell</td></tr></table>")); + assertEquals( + "<table><tbody><tr><td rowspan=\"4\">cell</td></tr></tbody></table>", + s.sanitize("<table><tr><td rowspan=\"4\">cell</td></tr></table>")); + assertEquals( + "<table><tbody><tr><td>cell</td></tr></tbody></table>", + s.sanitize("<table><tr><td colspan=\"three\">cell</td></tr></table>")); + assertEquals( + "<table><tbody><tr><td colspan=\"3\">cell</td></tr></tbody></table>", + s.sanitize("<table><tr><td colspan=\"3.5\">cell</td></tr></table>")); + } + @Test public static final void testLinks() { PolicyFactory s = Sanitizers.LINKS;