HtmlUnit 5.6.0: Security Hardening, Better Text Layout, and Web Crypto
November brings HtmlUnit 5.7.0 with Firefox 159, Firefox 153.5.0 ESR and Chrome/Edge 156 support. This release is a mix of security fixes, a large set of text and layout corrections that bring HtmlUnit’s output closer to real browsers, and a thorough cleanup of the Web Crypto API. Together with the Rhino team, we also continued fixing JavaScript engine issues.
🚀 Version 5.7.0 - November 2, 2026
Security Fixes
Several issues in this release were reported or found while hardening the parser and CSS engine:
- CSS regex backtracking: The url and position detection inside the
backgroundshorthand (used bybackgroundImageandbackgroundPosition) was vulnerable to regex backtracking (CWE-1333). Some long values could block processing for a very long time. This is fixed. - Authorization header forwarding: The
Authorizationheader is no longer forwarded to another origin, neither for redirects nor for requests of external scripts. Thanks to Vidya m for reporting this. - Parser and CSS nesting limits: The CSS parser limits the nesting depth of functions,
calc()blocks, and selectors to 32 levels. Deeper input is reported as a parse error instead of causing aStackOverflowError. The HTML tree builder limits the nesting depth of the generated document to 512 elements, like browsers do. - Denial of service protection in the HTML parser: Searches on the element stack are limited to 100 entries, so crafted input with a deep stack no longer causes quadratic parsing time. This is a behavior change: an end tag that would have to close more than 100 unclosed elements is now ignored.
- Scanner fix: A fuzzer found an
ArrayIndexOutOfBoundsExceptionwhen the input ends in the middle of the end tag of atitle,textarea,style, or similar element. This is fixed.
For more background on HtmlUnit’s security considerations, see the Details about HtmlUnit Security page.
Text Width and Layout
HtmlUnit now estimates the width of text based on the character widths of the default font (Times) used by browsers, instead of using a fixed width per character. This affects:
offsetWidthandclientWidthof shrink-to-fit elements- the left position of elements that follow some text
- the rects returned by
Range.getClientRects()andRange.getBoundingClientRect()
The results are much closer to real browsers. A new method, BrowserVersion.getTextWidth(String, String), exposes the estimate directly.
Related fixes to getBoundingClientRect() and Range handling:
- Ignored whitespace-only text nodes and block-level siblings when calculating the horizontal offset of a text node
- Shrink-wrap width calculation for block elements, returning a tight bounding box around the content
- Correct character offsets when range boundaries are set on a parent element
innerText, outerText, and getText()
A large part of this release reworks how text is extracted, both for the innerText/outerText properties and for WebDriver’s getText():
innerText and outerText now follow the innerText algorithm of the HTML spec:
- Required line breaks of block elements are merged and dropped at the start and end
- Paragraphs are surrounded by an empty line
bris a line break that is part of the content- Table cells are separated by a tab and table rows by a line break
- Inputs, images, and selects are treated as atomic inlines
- Options of a list box are placed on lines of their own
- Elements with
display: noneorcontent-visibility: hiddenare skipped - Fallback content of
canvas,meter,progress,iframe,video,audio, and (when JavaScript is enabled)noscriptis no longer included
getText() (DomNode.getVisibleText()):
- Line breaks around blocks are only added when the current line has content, like the Selenium atoms do
- Elements with zero opacity,
content-visibility: hidden, zero size with hidden overflow, or positions outside the page are not visible - White-space handling reworked:
preandpre-wrappreserve spaces,normalandnowrapcollapse them, and zero-width spaces are removed - Fixes for
select,option, lists, tables (including CSS table cells and footers placed before the body), closeddetails, SVG,iframe, andbr
Visibility and display:
isDisplayed()now handles thehiddenattribute and the open state of adialogthrough the computed display style; an explicit display style overrides bothgetDisplay()returnsnonefor a closed dialog andblockfor an open one
HTML Parsing and Serialization
Parser behavior:
- A trailing slash on non-void elements is only honored for XHTML pages and XHTML fragments; in HTML documents it is ignored, like in browsers
- A NUL character is replaced by U+FFFD in the content of several elements and in comments and attribute values
- A line feed directly after the start tag of
pre,listing, andtextareais no longer part of the content - Elements like
<a>and<nobr>are un-nested like real browsers do, so<a href="1">1<div><a href="2">2</a></div></a>no longer produces nested anchors
SVG:
- The HTML parser now restores the case of SVG names listed in the HTML spec (for example
foreignObjectandclipPath) - The content of an SVG element set via
innerHTMLis parsed as SVG content createElementNS()keeps the case of the name
Serialization (innerHTML and outerHTML):
- XHTML and XML documents use the XML serialization: namespace declarations, empty elements written as
<foo/>, void elements as<br /> - Attribute values are escaped like in real browsers
- Text of raw text elements such as
iframe,xmp, andnoscriptis no longer escaped - Processing instructions end with
>(Firefox) or?>(Chrome/Edge) XmlUtils.escapeHtmlAttributeValue()andXmlUtils.escapeXmlAttributeValue()are now available
Attributes and properties:
setAttribute()lowercases the attribute name in HTML documents- Setting
disabled = truesets the attribute to an empty string, and an existing value is kept createCDATASection()throws aNotSupportedErrorfor HTML documentsDOMImplementation.createDocument()treats a null namespace as no namespace
Web Crypto (SubtleCrypto)
The Web Crypto API received a thorough review. Highlights:
- Error handling: Invalid input is now rejected with the correct error types:
TypeErrorfor invalid arguments,DataErrorfor invalid key data, andOperationErrorfor failing operations. Decryption failures no longer throw anArrayIndexOutOfBoundsException. - AES-CTR now increments only the rightmost
lengthbits of the counter block. - CryptoKey:
algorithmandusagesreturn the same object on every access, and changing these objects no longer changes the key’s behavior. - Algorithm names are matched case-insensitively, like in real browsers. Keys report the registered name, for example
"AES-GCM". importKey()accepts the algorithm as a string.verify()resolves tofalsefor an RSA signature that does not match the modulus length.crypto.getRandomValues()now fills the array bytes directly. PreviouslyUint8ClampedArrayreceived only the values 0 and 255, andBigInt64Array/BigUint64Arrayreceived only 32 random bits per element.
Downloads and File Names
A new ContentDispositionParser parses the Content-Disposition header according to RFC 6266, RFC 2183, and RFC 8187.
AttachmentHandler.isAttachment()detects the disposition type the way browsers do. Responses withapplication/octet-streamare always handled as attachments.Attachment.getSuggestedFilename()now determines file names like browsers do: case-insensitive parameter names, quoted strings,filename*taking precedence overfilename, unsafe characters replaced by_, and leading and trailing dots and whitespace removed.WebDriverTestCasesupports testing file downloads with real browsers (needDownloads()) and optional WebDriver BiDi runs.
XMLHttpRequest and DOM
- Added the Firefox properties
mozAnonandmozSystem(alwaysfalse) - Added the Chrome/Edge methods
setAttributionReporting()andsetPrivateToken()(argument and state checks only) - Added
responseURL getResponseHeader()returnsnullfor a network-error responseresponseTextis an empty string after a failed redirect- A same-origin or initial XHR that follows a 3xx redirect to a cross-origin resource without proper CORS headers is now blocked
- Added
DOMImplementation.createHTMLDocument(),HTMLDocument.appendChild(), and simple implementations ofcreateAttributeNS(),createEntityReference(), andcreateProcessingInstruction() - Added the CSS pseudo-class
:scope; pseudo-class selector validation is now case-insensitive - Added CSS media query resolution unit
xas an alias fordppx(issue #992)
JavaScript Engine
Together with the Rhino team:
- super property increment/decrement operator fixed
- catch scope fixes
BigInt.prototype.toLocaleString()no longer treats its argument as a radixJSON.parse()andJSON.stringify()callbacks receive numeric keys correctlyTypedArray.prototype.subarrayhandles infinite and large indexes correctly- Converting the smallest subnormal numbers to strings is fixed
TypedArray.prototype.withreads the length before coercing its argumentsArrayBuffertransfer methods no longer use the species constructorObject.fromEntries()no longer stores array index keys as named propertiesFunction.prototype.toString()keeps the name of object literal methods- Several more fixes for lexical scoping and
FinalizationRegistry - Convenience methods for manipulating Promises from Java were added
I also fixed several inconsistencies in Math.
PerformanceObserver
PerformanceObserver now supports observe(), disconnect(), takeRecords(), and supportedEntryTypes, including the argument validation of real browsers (issue #1136). HtmlUnit does not record performance entries, so the callback is never called.
Content Security Policy
Thanks to kingthorin, the CSP support gained Trusted Types query methods:
enforcesTrustedTypesForScript()allowsTrustedTypesPolicyName(String)allowsAnyTrustedTypesPolicyName()allowsDuplicateTrustedTypesPolicies()
Two warnings were corrected: the warning for an empty trusted-types directive now states that it blocks all policy names, and the incorrect “‘allow-duplicates’ is redundant” warning is removed.
Other Changes
MockWebConnectionis nowSerializable. Thanks to Vladimir Babin (issue #91).- Chrome/Edge:
FontFaceSetand the SVGTEXTPATH_SIDETYPE_*constants are available. - Firefox:
Notificationconstants andError.stackTraceLimit-related updates. CSSStyleDeclarationandComputedCssStyleDeclarationreceived optimizations and fixes.- Several
HTMLTagBalancerperformance improvements, including O(1) “is element open” checks.
Version 5.7.0 is available on Maven Central. Check out the full changes report for the complete list of changes.
Happy testing!
— RBRi
Resources:
- Changes Report — Detailed release notes
- Details about HtmlUnit Security — Security considerations
- HtmlUnit Homepage — Project information
- Maven Central — Download
- GitHub Repository — Source code