Executive Summary

Jim Manico, project lead at OWASP, has just released new versions of two libraries that, in his view, are still widely used but often forgotten: OWASP Java Encoder (1.6.0) and OWASP Java HTML Sanitizer (20261011.1). His write-up on Foojay boils down to one simple request to Java developers: please update, and if you're using them in production, give feedback.

The Problem It Solves

These two libraries address two different sides of the XSS problem. Java Encoder is used when we want to block all dangerous markup by encoding according to the output context — encoding for text inside an HTML element is different from encoding for a value inside an HTML attribute, and its API forces us to explicitly pick the right context. Java HTML Sanitizer is used for the opposite case: when users are actually allowed to submit formatted HTML (a comment with bold text, a description with paragraphs), and we don't want to encode everything into raw text, but still need to strip out dangerous tags and attributes according to a policy we define ourselves.

Key Features and Code Examples

Java Encoder 1.6.0 (org.owasp.encoder:encoder) has no runtime dependency and still supports Java 8+. Here's an example of the two most common output contexts:

import org.owasp.encoder.Encode;

public class EncoderExample {
    public static void main(String[] args) {
        String name = "Jim & <friends>";

        String paragraph = "<p>" + Encode.forHtmlContent(name) + "</p>";
        String input = "<input value=\""
                + Encode.forHtmlAttribute(name) + "\">";

        System.out.println(paragraph);
        System.out.println(input);
    }
}

What's interesting in the changelog: the previous 1.5.0 release fixed a security bug where an already-encoded fragment, when placed right next to trusted text, could combine to form a dangerous HTML/XML delimiter — the encoder only sees the value we give it, while the browser sees the assembled page. 1.6.0 itself isn't a new security fix, but it smooths out the JavaScript encoders (general and block) by reducing escaping of characters that didn't actually need it. The public API and the Java 8 baseline haven't changed, but the encoded byte output and some streaming behavior have — so if you have tests that compare the encoded string with an exact match, those need to be rechecked. If you're using EncodedWriter with the general/block JavaScript encoder, don't forget to flush before writing directly to the underlying writer. One more thing worth noting: the encoder-esapi adapter has been retired and no longer has a supported version, so anyone still using it is advised to migrate via the ESAPI adapter migration guide provided by the project.

For HTML Sanitizer (com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer, version 20261011.1), a basic policy looks roughly like this:

import org.owasp.html.HtmlPolicyBuilder;
import org.owasp.html.PolicyFactory;

public class SanitizerExample {
    public static void main(String[] args) {
        PolicyFactory policy = new HtmlPolicyBuilder()
                .allowElements("p", "strong", "em")
                .toFactory();

        String submittedHtml = "<p>Hello <strong>Java</strong>!"
                + "<img src=x onerror=alert(1)></p>";

        System.out.println(policy.sanitize(submittedHtml));
    }
}

The result is simply <p>Hello <strong>Java</strong>!</p> — the img tag with onerror is automatically stripped because it's not allow-listed. The latest releases have focused on HTML and CSS parsing robustness: there's an advisory about CSS functions nested too deeply, which could exhaust the thread stack while the sanitizer processes the style attribute — this has been capped via a nesting limit in version 20260924.1. The latest version, 20261011.1, is more of a packaging fix: the Java 10 compatibility implementation was moved into a versioned directory inside the JAR and one unnecessary class was removed, so Java 8 builds using the Maven Enforcer rule enforceBytecodeVersion (default, non-strict mode) no longer need a workaround for those two classes.

Impact and Upgrade Notes

Neither library has a breaking API change, but Manico recommends two concrete steps before just bumping the version. First, check the version that's actually resolved in your application — the dependency can come in transitively through another library, so the version in one POM isn't necessarily the version running in production. Second, run the upgrade against real-world scenarios: for Encoder, re-check the output contexts you use and any tests that depend on an exact-byte match of the encoded result; for Sanitizer, test the policy against real editor output, reasonable formatting, and the malformed input that's usually already in your regression tests, including representative CSS if styling is allowed. For those still using JSP, make sure the core and JSP adapter versions stay in sync, and pick the adapter that matches the javax or Jakarta API in your respective container.

---

First announced on Foojay.io (Friends of OpenJDK). Read the original source for full details.

Read also